目录
前言:
我们在前一章就开始学习与进程相关的部分知识,上一章是先学习到了进程优先级接下来就是补充一些额外知识。
命令行参数:
现象:
我们是否还记得,我们在刚开始学习C语言的时候,对于main函数的写法我是介绍过的,我记得我说过main函数可以写成这样:int main(int argc, char* argv[]) 。我们当然是可以选择这样写也可以直接选择int main()这样直接完事。下面我们来看下列的代码:
输出结果:
当然我们还可以再尝试一下:
输入指令:./test -a -b -c -d
这些参数的意义:
我们在通过点斜杠运行可执行程序后,通过添加-a或者-b这样的参数即可看到argc和argv的变化,其实这些是和该进程匹配的选项,这些选项以这些空格作为分隔符,把他们放进一个指针数组里。
其实作为区分的本质是将空格转换成'\0'加以区分的!
为什么要这么做?
可以通过输入不一样的选项,执行同一份代码的不同功能。以下通过代码举例子:
命令行参数本质是交给我们程序不同的选项,用来定制不同的程序功能。命令中会携带很多选项。
这些事是谁做的呢?
主要还是由我们的父进程bash(命令行解释器)管理,所以我们就可以得出以下结论:父进程的数据,默认能够被子进程看到并访问。命令行中启动的进程,都会变成进程,其实都是bash的子进程。
所以对我们之前通过点斜杠 运行的可执行程序,默认是输入给父进程bash的。
因为子进程能看到父进程的数据,因此bash在识别几个-a -b -c后传递到argc,并再malloc出argv[],这些都是子进程能看到的。现在我们也能理解,为什么有些指令类似ls后面还会有一个-l或者-a这样的选项的意思了。
环境变量
环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数,如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性。相信大家如果配置过java或者嵌入式stm环境得物时候为这个环境变量抓狂过,接下来我们就来了解下环境变量!
现象:
在Linxu中,存在一些全局的设置,表明告诉bash(命令行解释器),应该在哪些路径下去寻找可执行程序。
我们可以尝试输入指令:echo $PATH
系统中有很多配置,在我们登录Linux系统的时候,就已经被加载到了bash进程中(在内存中的),默认查找到的环境变量是内存级的。
PATH其实环境变量的一种,而我们$PATH无非就是将环境变量的内容存放地打印出来,我们将结果打印出来的内容:PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/ws/.local/bin:/home/ws/bin
这一串就是表示了各个环境变量存放的位置,比如/usr/local/bin这个文件夹,里面的可执行程序在该文件夹中,就代表了环境变量。其中 ":" 表示分隔符,bash在执行命令的时候,需要先找到命令,因为未来要加载。
刚刚我们讲命令行参数时,其实就有疑问了,运行test可执行程序时是要加点斜杠 的,再加上-a -b之类的选项,然后我说这可以说明ls为什么有-l -a选项对应不同的功能。此时我们就会发现,ls这个指令就不用加点斜杠 运行, 这又是为什么呢?
其实这个就是讲解环境变量最好的例子,这是因为bash会先去各个地址找,然后发现了ls在/usr/bin目录中
然后就会调用ls,所以在执行ls时就不用加点斜杠。
创建环境变量:
若是,我想要自己的可执行程序和系统指令一样,不带点斜杠该怎么办呢?目前我们介绍三种方法。
1、可以尝试使用cp命令,将自己的可执行程序拷贝到/usr/bin目录下。
首先我需要给我的test可执行程序改名字,因为/usr/bin目录下有test这个环境变量。目前我们单独使用my_test是不起作用的,which也没有结果。所以我们开始进行拷贝。
演示成功啊,运行成功,和上面演示的一样。
2、也可以直接PATH =$PATH:"自己当前的目录",对于我的目录我就可以写成:
当然这种方式慎用,但是也没关系。因为我们每一次重启,环境变量右会重新归为。这是因为最开始的环境变量并不是在内存中的,而是在系统的对应配置文件中(默认在配置文件中)。
这个配置文件就在用户家目录下,.bash_profile文件、.bashrc文件和/etc/bashrc文件。其中前两个是用户的配置文件,最后一个是系统的配置文件。
所以如果我们想要永久更改环境变量的路径,可以直接在.bash_profile里更改。
见见更多的环境变量
可以输入:env 查看全部的环境变量。
这些环境变量都是极其准备好的。
export "环境变量名" = "环境变量内容" ------ 添加
unset "环境变量" ------ 取消
结合程序理解:
环境变量默认是可以被子进程拿到的!因为环境变量们,默认实是在bash里的。
而这些环境变量均是全局的!
环境变量有那么多,bash内部是如何组织的呢?
其本质是有一串代码组织的,extern char** environ;
接下来通过代码演示一下
不难发现,通过代码发现和我们直接输入env这个指令没有区别的。
bash再进程启动的时候,默认会给我子进程形成两张表:
argv[ ]命令行参数表(从用户输入命令行获取),env[ ]环境变量表(从OS的配置文件获取),bash通过各种方式交给子进程。
所以我们对于命令export XXX = XXX就是去env[ ]表里寻找NULL的地方,然后链入新的环境变量即可。
环境变量具有系统级的全局属性,因为环境变量本身会被子进程继承下去
以下是获取环境变量的三种方法:
- char* path = getenv("PATH")
- 通过main函数参数char* env[ ]
- extern char** environ
在执行export添加新环境变量时不会创建子进程吗?
子进程自己的数据bash看不到,但是export新的环境变量bash是可以看到的。当然执行export不会创建子进程,echo也不会创建子进程。这是因为export和echo是属于内建命令,这些命令是会有bash亲自执行。但是这只是一部分,因为80%的命令都是由bash创建子进程,子进程来执行的。
对于内建命令,可以理解为bash内部的一个个void类型的函数,执行完就执行完,并没有返回值。
注意!!!
如果你只是在输入指令:HELLO = 1234 这样子输入,你本质只是创建了一个本地变量 ,而不是环境变量!你可以使用echo $HELLO打印出来
但是你无法通过env|grep HELLO 查找出来,通过main函数或者extern char** environ这两种方法也查找不到!
本地变量只在ash内部有效,无法被子进程继承下去。只要导成环境变量,此时才能够被获取。