不知道大家有没有思考过当我们的程序编译链接成功后,需要./xxx让这个可执行程序跑起来,那为什么不能是xxx呢?
这是因为我们所写的命令、程序……都是文件,当我们执行自己的程序的时候,是需要./xxx来确定路径找到对应的程序,./就是告诉操作系统这个可执行程序就位于当前目录下。
而为什么我们在执行系统命令的时候是不需要带路径呢?就比如我们的ll、ls、mv等指令,直接用ls即可?
这是因为环境变量PATH的原因,系统通过环境变量PATH来找到ls命令的。也就是说ls命令就在PATH环境变量的默认路径下。环境变量的本质是操作系统在内存/磁盘文件中开辟的空间,用来保存系统相关的数据。
如下图所示,环境变量PATH以:为分割符,分割出多条路径,执行的时候从左往右依次查找,直到找到为止。
而我们的ls命令在usr/bin这个路径下,也就是这个系统命令实际就位于环境变量PATH中的某一路径下,所以就算不带路径,系统依靠环境变量PATH也是能够找到的。
而为什么我们不能直接运行自己的可执行程序呢?这是因为我们的可执行程序没有放到环境变量路径里面的路径!所以我们有以下两种方法:
No.1:把可执行程序拷贝在环境变量PATH的某一路径下,但因为会污染命令池。
也就是既然我们在没有指定路径的情况下系统会根据环境变量PATH当中的路径去查找,那我们就可以将我们的可执行程序拷贝到PATH的某一路径下,此后我们的可执行程序就不带路径系统也可以找到了!
sudo cp proc /usr/bin
No2、把我们的当前路径添加到环境变量PATH(可)
也就是简单暴力地将这个可执行程序所在的目录直接导入到环境变量PATH中,让PATH从左往右找路径,找到即可。
我们利用第二种方法来试一试:
export PATH=$PATH:当前路径
当然大家也不用担心这个环境变量加进去以后会一直占用,我们只需要重新登录一次我们的当前Linux账号环境变量就会恢复如初,因为这个修改环境变量仅仅是对此次登录有效,只要我们不动配置文件,不会出问题的。
环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数。是系统提供的一组name=value形式的变量,不同的环境变量有不同的属性,通常具有全局属性。
如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性
我们在Linux中所敲的各种命令,实际上是需要命令行解释器进行解释的,而在linux中有许多命令行解释器如bash、sh等,我们可以通过查看环境变量SHELL来知道自己当前所用的命令行解释类型。
其实命令行解释器实际上就是系统当中的一条命令,当这个命令运行起来变成进程后就可以为我们进行命令行解释。
本地变量不会被子进程继承,只在本bash内部有效。内建命令属于shell执行的一部分,因此执行内建命令不需要创建子进程,也不需要打开程序文件,这样不用操作文件IO,执行效率高,运行快。
MYVAL=100
echo $MYVAL
接下来有一个奇葩的现象,echo是bash的子进程没毛病,我们不是说本地变量MYVAL不会被子进程继承吗?我们的命令echo后面不是需要创建一个子进程吗?那么我们的echo $MYVAL需不需要创建一个子进程?为什么最终echo运行的时候把本地变量给打印出来了?
分类:两批命令:1、常规命令(通过创建子进程完成的) 2、内建命令(bash不创建子进程,而是由自己亲自执行的,类似于bash调用了自己写的或者是系统提供的函数)
所以在本bash中依靠内建命令即可完成echo的打印。
每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以’\0’结尾的环境字符串
考察大家一个知识点,main函数中的()里面是有参数的吗?答案是有,而且有三个!我们先来讲解前两个,最后再讲解第三个!
argc:命令行字符串的个数
argv:指针数组
这就是一个指针数组,argc自动计算指针数组的个数,而argv存着每一个指针,指向我们命令行中**以空格间隔的字符串。**即为指令、工具、软件等提供命令行选项的支持!
那么我们的命令行参数意义在哪里呢?
我们知道命令是带有很多选项的,完成一个命令的不同子功能。选项底层就是通过命令行参数实现的。也就是说,我们的ls -l这个指令是先ls再-l去找计算机内部的选项的,用来完成打印出详细信息的选项。
我们在第三章节的环境变量的组织方式中已经提到过环境变量的概念,所有的环境变量就是一个字符数组指针,指向不同的函数,来展示不同的功能。那么我们就能够用main函数中的第三个变量env来进行查看一下当前linux配置下的环境是怎么样的(刚好是单打env命令):
我们除了使用第三个函数变量envp后,还可以用第三方environ来看环境变量的。
注意:libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时 要用extern声明。
上面两种环境变量方式不常用,近乎不用,这里只是为了介绍环境变量的获取方式而已。
注意:我们所运行的进程都是子进程,bash本身在启动的时候,会从操作系统的配置文件中读取环境变量信息。
环境变量是从父进程继承得来,慢慢追溯到bash,甚至操作系统。
环境变量通常具有全局属性,可以被子进程继承下去。
可以看到PID一直在变,因为子进程在不断新建,但PPID保持不变,而它的父进程就是-bash,即命令行解释器。命令行上启动的进程,父进程都是bash。 操作系统都会记住子进程的!
本地变量 && 环境变量
最后执行命令是,打印出来环境变量,bash给我们创建子进程,./proc为子进程,也就证明了:
子进程继承了父进程的环境变量
子进程的环境变量是从父进程来的,追溯到bash