本章目标
1.命令行参数
2.环境变量
3.修改bashrc
4.内建命令
1.命令行参数
在我们之前的main函数本身是没有任何参数的,但是关于这个函数的入口它本身是由参数的,一共有三个,在这里我们先说前两个,
int argc和char* argv[]这两个参数,他们分别表示为命令行参数个数以及命令行参数,

当我们的这个程序被编译成二进制可执行文件之后,启动的时候,我们bash会将我们的命令行默认给到这个进程.一般来说argc这个值是至少为1,argv的第一个参数它表示的是我们的进程名.
当我们以./testenv的方式去启动这进程的时候,它的argc为1.走了第一个分支直接返回
当我们以./testenv后面跟上以空格分开的字符串的时候,我们的bash会将这个字符串以空格为分隔符进行分割.然后argc去统计一共分了多少个子串,而argv存放的就是每一个字串,但是在argv这个数组中,最后一个元素默认为NULL,这个位置也就是argv[argc].

那么为什么要有这个命令行参数呢
在前面我们说过,我们的所有命令实际上都是一个个可执行文件.他们被统一放到
/user/bin这个路径下.举个例子,我们通过
ls -a -l
这个命令去查看当前工作目录的具体信息.
这个命令行就会被bash解析成一个个字串放到argv当中,再将统计整个argv的个数放到argc当中.这个过程我们一般是不可见的.它是由bash自主完成的.
我们的命令既然是一个可执行文件.它启动的时候就一定会创建进程,而这个进程是bash通过系统调用创建出来的子进程.而这个时候bash会将处理好的命令行参数和命令行参数个数交给这个进程.进程再根据这两个参数去区分要具体执行哪个功能.
所以命令行参数的意义就是为了为让一个命令能够通过选项实现不同的功能.

2.环境变量
我们之前说过我们要执行一个命令一般要指定路径

想这个./就是告诉操作系统当前命令再当前目录中,
而有一些命令向ls,这种命令,我们就不需要指定路径,这些命令当我们执行的时候,操作系统会从user/bin这个路径下去寻找这个命令.
那么操作系统是通过什么找到这个这个路径的呢,
在我们的linux系统中,为了解决这个问题引入了环境变量PATH,我们可以通过PATH去查看这个环境变量的内容,这个,符号可以理解成语言层面上的解引用,这个实际上是shell自身的脚本语言.

我们可以通过echo去查看这个环境变量和自身的内容.
当我们去执行类似于ls ,gcc,gdb,这种命令的时候,操作系统会先去这几个路径下的目录进行检索,去找这个命令当这个命令被找到就会用这个路径去拼接上执行.
我们想要实现像ls这样的命令的执行方式,我们不仅可以直接将可执行文件放到特定的路径下,像/user/bin这种目录下,但是这种方式我们并不推荐,这种操作会污染命令池.
我们可以通过将可执行文件的工作路径添加到这个目录当中.
在PATH这个环境变量当中,如果我们直接将目录复制赋值给PATH这个环境变量,这样并不会成功.这样是覆盖.我们一会演示一下这个操作.
我们可以看出这个PATH环境变量的内容是通过:进行分割的.

正确的做法是PATH = $PATH:目录

如果直接赋值这个环境变量会直接覆盖,如果找不到原先的路径直接重新启动bash即可.
这个修改的相当于当前终端的环境变量,并没有修改成全局的,它是在内存当中的,被bash所获得的.

我们重新启动的时候就重新变回原先的样子了
那么既然在Linux当中有这个概念,在window当中也存在同样的概念,它既然作为一款操作系统也会有同样的问题.

我们想要通过命令行去启动一个程序.可以将改程序的地址写入到环境变量当中,在window当中,上面的用户变量可以理解成在Linux当中的bash的环境变量,下面的则是当前用户全局的环境变量,同样的可以理解成Linux当中的每一个用户的bashrc,它是作用到全局的,到后面我们会解释这个东西.

当我们设置完通过,在当前文件夹当中的可执行文件的名称,直接就能够启动当前程序的进程.
在之前我们的qt或者是java,python这种框架或者语言,minGW这种工具链或多或少的大家都会去配置这个环境变量,我相信大家一看就懂
回到Linux当中,我们要像知道其他的环境变量可以通过env这个命令去获取所有的环境变量

有一些环境变量并不会显示再这里例如动态库加载的哪个LD_LIBRARY_PATH,在这里我们具体介绍介个
PWD
HOME
OLDPWD
SHELL
我们之前说过,我们打开fopen默认不给路径的话,进程会从自身的pcb找,那么是谁给pcb的是bash,当一个进程创建的是时候,是通过bash1创建子进程的方式创建的进程,它同样的也就继承了bash的环境变量.
我们之前有关cd ~和cd -分别是返回家目录和上级目录,这两个命令实际上就是从HOME和OLDPWD这两个变量中获取路径然后去通过这两个路径进行跳转.
SHELL全称是命令行解释器.
在这里我们的命令行解释器user/bin/路径下的bash.
后序在我们进程全部结束,我们会写一个迷你版本的shell,仿照linux的bash.
我们既然可以通过命令的方式获取环境变量.也可以通过代码的方式获取环境变量
1.通过main函数的参数
我们在第一个小节说过main函数是有参数的前两个参数分别是命令行参数个数,以及命令行参数个数.命令行参数.
它其实还要第三个参数就是环境变量,它也是一个char*类型的数组,它会将当前所有的环境变量放到这个数组当中,最后一个元素也是为NULL,我们现在演示一下.

我们可以通过给前两个参数强转来消除警告

我们同样可以拿到这个所有的环境变量
我们也可以通过在stdlib,也就是c标准库当中给我们已经定义好的一个变量
environ 来去访问这个环境变量表,我这种方式就是不用给main函数传参了,这也就是说明,这个环境变量表在进程启动前就已经有了.

这个变量是一个char**的environ,它拿到的实际上就是这个环境变量表的地址,在c中我们数组传参实际上要进行升维.它实际的结构是这个样子的

我们也可以通过系统调用去获取到环境变量

这个系统调用,我们至于要吧我们需要的环境变量以字符串的形式传进去,如果匹配了找到了就返回返回我们环境变量的内容,没有找到就返回一个空指针


我们的环境变量最大的特点,它是全局的,它是通过bash创建子进程的方式传递给下一个进程,因为fork出来的进程,是能够看到则个环境变量的

为了证明这一点,我们可以用bash本地变量和环境变量做对比

我们可以像这样设置一个本地变量,我们同样可以去拿到这个本地变量的内容
我们用刚才用到的系统调用去查一下这个a


我们可以看到我们是找不到这个变量的.
然后我们可以通过export 将我们的本地变量导入我们的环境变量当中,

我们可以看到,我们是能够找到这个环境变量的.
我们可以看到我们的环境变量是全局的,我们再通过env找一下这个a

这样我们再bash中和进程中都能够找到这个a就足够证明,我们的环境变量是全局的

我们也可以通过unset 命令去取消环境变量,这样我们就找不到这个a了
但是我们这个几个操作都是内存级,它不会影响其他终端.我们下面介绍如何进行修改
3.修改bashrc
其实在我们每一个用户的家目录下都会创建两个隐藏文件

但是我们今天用的是Ubuntu,它并不会去创建另一个bash_profile,但是这个不影响
我们每一次登入用户的时候,我们创建bash会先去读取这个.bashrc这个配置文件去加载环境变量.这个配置文件回去加载/etc/的bashrc和profile,我们只要修改这两个其种一个就可以应用到全局

我们现在改一下

修改全局的配置需要root账号的权限

我们设置一个环境变量然后输入一句话

我们看到了这个话,然后找一下这个环境变量

同样可以找到.
4.内建命令
我们的命令,在我们之前说过,它是一个二进制可执行文件
但是我们的命令与命令之间也存在不同.有些命令即使不需要路径也能够调用,它是bash内部的函数调用.这种我们称之为内建命令
我们现在演示,为了模拟环境,我们给PATH环境变量删除

我们看到我们给环境变量删除之后cd , echo等命令能正常运行,这种就是内奸命令,而其他的不能够执行这种就是普通命令.