到了现在,我们也知道我们轻轻敲下ls指令,其实会转为一个可执行文件在运行,也就变成了一个进程,所以ls是让文件运行,./test也是让文件运行,凭什么我们的可执行文件就要加个./(这个./是告诉bashtest文件是在当前的目录下),ls没加路径,进程是怎么知道代码在哪的?
我们现在用which指令看看ls在哪,噢,ls是在/usr/bin下的一个可执行文件。这意味着我们也可以用usr/bin/ls执行ls指令,就像./test一样。难道说bash记住了ls文件在哪,当我们用的时候,默认去那找?那谁记住ls的路径呢?
原理就是这个环境变量——PATH,echo打印时要$,告诉echo这是个变量,不然会被当成字符串打印了。PATH变量中有/usr/bin路径,ls等指令运行就会去下面路径里找,找不到就报错。
所以如果我们把test文件的路径写到PATH变量中,那我们也就可以不带./,直接test就可以运行了。好,怎么加?
PATH=$PATH:/home/hqy这样/home/hqy下的可执行程序例如a.out就可以不带路径执行了。而且打印显示PATH这个环境变量,也会发现路径添加成功了。 PATH=$PATH:/home/hqy这种方式是追加路径,如果是如下写:PATH=/home/hqy则是覆盖写。
家目录,就是每个用户进入shell就开始在的目录
我们su一下,升级为root用户,password是让你输密码,不会会显到显示器,此时HOME也会变。
env显示全部的环境变量。
HISTIZE=3000是指会保留三千条历史指令,USER保存的当前用户名,然后就是一大段的字母,数字,都是ls的配色方案,ls指令显示目录会有颜色,应该是和这个方案有关。其它就不解释了。
值得注意的是,cwd不是环境变量,是进程的工作目录,有时候这个进程工作时会产生一些临时文件,这些临时文件要放在进程附近,所以就要记录进程的工作目录,把临时文件放在该目录下,可是我不是已经有环境变量pwd了吗?经过我测试,我觉得有一种场景,例如我在/home路径下去运行其它路径的可执行程序,这个时候的环境变量pwd内是/home,如果没有cwd,那这个可执行程序运行起来后产生的文件难道放在/home下吗,这就有点乱了吧。
这里简单介绍几个指令,会用即可,export创建一个环境变量,unset则是取消,env显示全部的环境变量
系统提供的具有全局属性的变量。如何体现的全局呢?首先当我们没运行进程的时候,bash可以显示环境变量,而且./test运行形成bash的子进程的时候也能获得环境变量,这是因为环境变量本质是数据,父进程的会共享给子进程,所以不断地父传子,环境变量就存在所有的进程中了,如果谁要修改,发现写时拷贝即可,至于是全部拷贝还是只拷贝一部分,在后续学习页表结构再来解释这个问题。
环境变量和我们写的程序文件例如test.c有什么关系呢?我在vs写了这么久的代码,我怎么从来没见过环境变量。要说关系,我们就得先说说main函数的参数了,对,main函数是有参数的,参数如下。
1 #include
2 #include
3 int main(int argc , char*argv[])
4 {
5 int i = 0;
6 for(; i < argc; i++)
7 {
8 printf("argv[%d]: %s\n",i,argv[i]);
9 }
10 return 0;
11 }
argv看类型好像是个指针数组,那我们打印一下里面的东西,这不是我们输入的命令吗?
这么看来./test 1 2 3会被bash解析为一个个空格隔开的字符串,然后一个个存到一个数组中,最后将数组名传给main函数,好,问题来了,一般函数传参形参没有写参数不是会报错吗,为什么我写了这么多代码没事。简单理解就是main函数是bash起的其它函数调用的,如果一开始发现你main没写参数就不给你传参。
命令行参数是bash根据输入的指令分割的传过去的,意义?可用于选项,做定制化功能。例如ls -l,实际上ls是有多个细分功能的,例如ls -d 显示当前目录,ls - l显示当前目录下的子目录和文件信息,所以为了让使用者能自己选择ls执行的功能,也就有了选项,我们输入指令时,选项可以按空格隔开输入,当然bash的一些指令的选项可以中间无间隙,不知道咋切割的,然后shell会解析这个指令,在ls代码中去匹配要执行的代码块。那和环境变量有什么关系?他们都是main函数的参数。mian函数的第三个参数,env
env也是个指针数组,打印一看,居然就是环境变量,那看来我们不仅可以通过getenv获取环境变量,还可以通过main函数的参数环境变量表来获取。
1 #include
2 #include
3 #include
4 #include
5 int main(int argc , char*argv[],char*env[])
6 {
7 int j = 0;
8 for(; env[j]; j++)
9 {
10 printf("%s\n",env[j]);
11 }
12 return 0;
13 }
全局属性是什么意思呢?linux下所有的进程都是bash的子进程,那bash的环境变量就会被子进程共享,这样不断地父传子,只要后续进程不改环境变量,bash的环境变量在所有进程中都能看见,这就是全局属性。
(1)cd
有些可执行程序不适合让子进程执行,例如cd命令,本意是改变bash的目录,如果起了个进程去执行,就会改成子进程的工作目录cwd,那就不会影响bash这个父进程的工作目录,在shell的实现上是写一个函数去调用chdir这个系统调用去更改工作目录,然后更新环境变量,不创建子进程,我测试了一下发现,ls显示的是工作目录下的具体信息。我突然就感觉我以为在shell下面cd好像是在各个目录下穿来穿去,其实一直在原地踏步,只改变了进程的cwd,然后更新了一下环境变量,ls,pwd显示的时候分别根据cwd,PWD把对应信息显示出来。
(2) echo
在linux还有种变量叫本地变量,这种变量不会被子进程共享,可是用echo又可以打印本地变量,这好像说明echo也是内建命令,但是系统中的echo要支持重定向,就要让子进程去重定向,免得影响了父进程。(这一点要在后续提到文件和shell实现才能体会得更深刻)
(3)export
export肯定是给bash自己导环境变量了,如果让子进程执行,那和bash有什么关系。