linux进程——解析命令行参数——环境变量详解

        前言:本节内容还是linux进程, 主要讲解里面的环境变量——我们首先要知道的就是环境变量其实就是操作系统维护的一组kv值, 环境变量是系统提供的一组 变量名=变量值 形式的变量。不同的环境变量之间具有不同的用途, 并且具有全局属性。 本篇内容主要分为两个大板块——第一个大板块主要是具体举几个环境变量的例子、第二个大板块主要是讲解环境变量的概念与知识点。

        ps:本节内容适合了解进程PCB的友友进行观看      

目录

PATH

HOME

SHELL

getnev

什么是环境变量

命令行参数

命令行参数里的环境变量

本地变量与内建命令


PATH

        我们以前说过, 指令的本质就是一个进程。 而且, 我们以前也说过, 我们自己写的程序必须加上./, 而指令不需要./——请问这是为什么呢?

        这是因为, 系统当中, 针对我们指令的搜索, 我们的系统会为它提供一个环境变量——PATH, 我们可以使用echo $PATH打印。 (注意, 这里的$符号不能去掉, 因为不加$就意味着echo会将PATH当作一个字符串进行打印)。这个时候, 打印的内容里面包含一串串路径, 并且这些路径用“:”进行分割, 这里面的每一条路径都对应着我们的指令进行搜索的路径。如下图;

        也就是说, 我们的系统怎么知道我们都是用的指令在哪里寻找呢? 就是因为PATH, 当我们调用某个指令的时候, 系统会进入PATH显示的每一个路径里面一个一个进行查找。 没找到就继续下一个, 没找到就继续下一个。 而如果某个程序被放到这些路径下面, 那么系统默认就会找到(就比如我们使用的指令 就是放到这里面的), 而如果某个程序没有被放到这些路径下面, 系统默认就找不到, 就会返回commend no found。 而如果想要运行这个程序就要输入这个程序的相对路径(就比如我们运行我们自己写的程序, 就是使用./程序, 这就是相对路径)

        想要在环境变量的路径中添加路径怎么做呢?

        就是使用PATH=$PATH:新添路径——其实这里的等号后面的路径就相当于PATH的新路径, 如果等号后面的PATH不要了, 只要添加新的路径, 那么新路径就不是现在这样既有PATH原本的路径, 又有新添路径了, 而是只有一个新路径。 

        注意:此时所修改的环境变量是内存级的环境变量, 想要变回来只需要重新启动一下xshell。

        综上:PATH:linux系统指令的搜索路径。

        windows下面的同样有环境变量, 事实上, 当我们使用python、java这些解释型语言的时候, 都需要配置环境变量, 而windows下面的环境变量的修改方法如下:

HOME

如图我们登陆了普通用户, 并且可以使用pwd查看当前当前目录, 同时我们使用echo $HOME;

也可以看到当前的目录。 

一个用户默认登录的进入的是用户的家目录, 那么为什么会这样呢?

因为一个用户在登录时, 系统默认识别$HOME命令, 查看当前用户的家目录在哪里, 当我们登录的时候, 就默认执行了cd $HOME指令进入了用户的家目录下。

SHELL

$SHELL可以查看当前命令行用的是什么, 即, 当前shell用的是哪一个可执行程序。

其他的, 还有很多的环境变量, env指令可以查看当前自己的进程和bash进程从系统继承下来的所有环境变量


 

getnev

通过c语言, c++我们也可以通过getenv函数获取某个环境变量。 

那么环境变量在权限中的应用?

如何就是通过getnev获取当前用户, 获取用户后和root账户做对比, 根据if else语句判断是不是root账户, 并在if或者else代码块里面执行对应的动作。 通过这个, 我们就能更好的理解权限问题——对于一个文件或者某个指令的权限判断, 是拥有者, 还是所属组, 亦或者是其他人。

什么是环境变量

        关于什么是环境变量, 在前言中博主已经提到。 但是这里还要补充一点:环境变量其实是有一定的用途的, 比如当前用户的家目录在哪, 当前的用户是谁,指令的搜索路径是哪里, shell的可执行程序是哪个等等。 

        而要具体的理解环境变量, 需要先理解命令行参数。 下面我们先来理解一下命令行参数的概念。

命令行参数

      对于main函数来说, 其实它是可以有参数的, 如下:

int main(int argc, char* argv[]){}

        这里面的argv是一个指针数组, argc代表argv的数组元素个数。 argv里面的元素个数由argc决定。

        这里可以使用一个循环, 将argv里面的元素全部打印出来:

        然后我们运行这个程序, 或者运行这个程序的时候加上一些选项, 就能看到打印出来的结果分别是这样的:


 

        ps:这里有一个题外的问题——main函数是第一个被系统调用的函数吗?——不重要, 友友们自行跳过即可。

        为了回答这个问题, 我们就要思考如果main函数是第一个被调用的函数, 那么它是不是就势必不能被传参? 而我们的main函数是有参数的; 而且我们从c语言也说过第一个被系统调用的函数其实是叫做starUp的函数, 这个函数真正的无参。

        回到上面的图中, 想要知道为什么我们输入的选项越多, 打印的内容就越多,就涉及到了bash的知识点——其实我们在bash上面输入任何指令, 本质上都是在输入字符串。 就比如我们上面输入./process-7-11.exe -a -b -c, 这个其实就是输入了一个"./process-7-11.exe -a -b -c"字符串而已。 而bash在进行命令行解释的时候会将这些字符串按照空格进行分割, 这些字符串分成一个新的字符串一起传给main函数作为形参, 也就产生了下面这种效果, 然后for循环再依次打印。

bash命令行为什么要这么做呢?

我们来看一个程序, 就能知道bash为什么会这么做了:

我们运行这个程序, 就可以得到如下结果:

对比我们使用ls加选项的时候:

        对比上面的两个选项, 我们是不是就能发现, 我们常用的指令, 为什么要打上选项?是不是就是因为指令加选项 本质上都是运行一个程序, 只是根据不同的选项, 走到了不同的else if里面, 然后执行了对应的功能模块。 这就是指令选项的本质, 这就是命令行参数。——也就是说, 命令行参数的一个重要功能就是为指令、工具等提供命令行选项的支持!!!

        而只要需要选项, 那么就要用到命令行参数, 所以要有命令行参数——即命令行参数的意义就是, 为了让我们使用程序的时候根据不同的选项, 执行不同的操作。

        我们使用ls --help就能查看ls的所有选项

        也就是相当于我们自己编写的程序, 加上了一个--help选项

        最后要补充一点的就是对于argv来说, 它的最后一个元素默认是NULL,也就是说我们在上面程序模拟的时候, 其实是不需要使用if判断, 如下图:

        现在来看一个叫做向量表的概念。 这个向量表其实就是上面的argv, 类似下图:

知道了这些东西以后, 那么, 这里就可以回归正题——>环境变量。

命令行参数里的环境变量

        我们学习命令行参数不是无理头的, 命令行参数和环境变量具有一定的关系,在哪呢?——请问, 有没有人规定命令行参数只有argc, argv? 没有, 也就是说, main的参数可能还有别的。 那么, main函数还真有一个别的参数, 这个参数就叫做int* env[], 这个env[]里面保存的是main当前进程的所有环境变量。 而且, 这个env[]的结构这里也可以提一下——就是向量表。 也就是说, main函数的参数里, 有两张核心向量表, 一张用来保存选项, 一张用来保存环境变量!!!

        下面是实验:

        运行后, 就可以发现和我们使用env指令一样

综上, 我们以后再看待运行程序的时候, 就可以这么考虑——》一定是有一个startUp直接或者间接调用了main函数, 并将两张向量表, 一个选项表, 一个环境变量表传给了main函数。 然后main函数再跑起来。

        那么这里就有了结论, 首先我们知道我们自己运行的这个程序是一个子进程, 而bash是一个父进程。 但是我们在bash下使用env的时候和我们在子进程下打印的环境变量是一样的。 ——这个结论就是——我们所运行的程序, 都是子进程, bash本身在启动的时候,会从操作系统的配置文件中读取环境变量信息, bash再在自己的上下文中构建一个环境变量表。 当我们的子进程需要的话, 就可以将环境变量信息给子进程一份。也就是说, 子进程会继承父进程交给他的所有环境变量!!!这就是为什么环境变量具有全局属性——因为他会在子进程中一个一个地完整的继承下去。

        但是这里有一个问题, 就是环境变量也是数据, 我们知道进程之间是独立的。 而如果一个子进程想要修改环境变量, 那么就一定不能够影响父进程的环境变量(写时拷贝)

        那么,我们如何验证这些环境变量可以一个一个的传承下去呢?

        在这里我们可以自己添加一个环境变量——这里的变量有两种, 一种是直接变量名=变量, 这个是本地变量。 另一种是export变量名=变量, 这个是环境变量。 我们需要使用后者。

        

        这样, 就可以看到我们的环境变量了!但是, 这个环境变量是我们在bash上面创建的, 那么要验证环境变量的全局性, 就要看一下我们的子进程中有没有这个环境变量。那么有没有呢?答案是有的, 如下图:

        取消环境变量使用unset环境变量:

本地变量与内建命令

set指令可以查看当前shell中所有变量, 包括本地变量和环境变量

本地变量不会被继承, 只会在bash中被使用。 创建本地变量的方式上面已经提到, 就是变量名=变量

我们如何验证本地变量不会被继承呢? 这里, 我们来写一个程序:

这个程序可以打印环境变量

我们可以使用set, 查看当前到当前具有这个本地变量, 但是我们使用子进程进行查看的时候, 查看不到!

然后, 当我们把本地变量改成环境变量的时候, 就能查看到了:

以上, 就说明了本地变量不能被继承.

        那么, 看第二个问题:

        既然MY_VALUE是一个本地变量, 那么它就不能被子进程继承, 我们也知道, bash里面的指令, 其实就是一个个bash的子进程, 问题是, 为什么图中的echo可以打印出MY_VALUE呢?

        那么, 没有错, echo不是一个bash的子进程。 这里就可以纠正之前的一个认知错误, 那就是——bash里面的指令, 不全都是bash的子进程。

        命令其实分为两种:一种是常规指令, 通过创建子进程完成。 

                                        一种是内建命令, 这种命令bash不回去创建子进程, 而是自己亲自执行(就相当于我们自己写的程序, 但是没有fork子进程, 或者说bash调用了自己写的或者系统提供的函数。)

        我们可以通过cd来理解这个内建命令的概念:这里我们自己实现一个cd命令, 这里需要用到系统调用接口——chdir(const char* path)

原因就是因为我们自己写的程序是bash创建的子进程。 而cd是bash自己调用的本身代码块。 两者本质不一样, 但是我们同样可以看到我们自己写的程序的工作目录——就是proc进程查看里面的工作目录。 代码如下, 两次睡眠是为了我们进行更好的观察。

如图是刚刚运行程序, 这个时候工作路径还没有发生变化:

下图就是工作路径没有发生变化的时候子进程工作路径:

工作路径变化!说明子进程工作路径变化只改变自己, 而cd是是父进程, 它改变工作路径, 就意味着我们的命令路径变了!!!

在系统里面, 有一个变量, 可以让我们不适用main参数就打印全部的环境变量——environ, 使用如下:

打印结果如下:

以上, 就是本节全部内容, 下面是本节笔记:

  • 105
    点赞
  • 80
    收藏
    觉得还不错? 一键收藏
  • 75
    评论
Python中解析命令行参数可以使用标准库中的argparse模块。argparse模块提供了一种简单而灵活的方式来解析命令行参数,并为你创建帮助和用法消息。 下面是一个简单的示例,演示了如何使用argparse模块解析命令行参数: ```python import argparse # 创建一个ArgumentParser对象 parser = argparse.ArgumentParser(description='解析命令行参数示例') # 添加命令行参数 parser.add_argument('input', help='输入文件路径') parser.add_argument('output', help='输出文件路径') parser.add_argument('-v', '--verbose', action='store_true', help='显示详细信息') # 解析命令行参数 args = parser.parse_args() # 访问解析后的参数值 print('输入文件路径:', args.input) print('输出文件路径:', args.output) print('显示详细信息:', args.verbose) ``` 在上面的示例中,我们通过创建一个ArgumentParser对象来定义我们期望的命令行参数。然后,我们使用`add_argument()`方法添加了三个参数:`input`、`output`和`--verbose`。`input`和`output`是必需的位置参数,而`--verbose`是一个可选的开关。 最后,我们使用`parse_args()`方法解析命令行参数,并通过访问`args`对象来获取解析后的参数值。 要运行上述示例,可以在命令行中执行以下命令: ``` python script.py input.txt output.txt --verbose ``` 这将解析命令行参数,并输出相应的值。 希望这可以帮助到你!如果有更多问题,请随时提问。
评论 75
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值