命令行参数
我们知道,我们使用的指令它本质上也是一个程序,我们要执行这个指令,输入指令名然后回车即可执行;但是对于指令带选项,又是如何实现的呢?
问题:main
函数有没有参数?
在我们之前写代码的时候,我们知道
main
函数是程序的入口;但是操作系统在执行程序之前,会先执行一个入口函数(_start
),然后由这个入口函数去调用我们的main
函数。那我们的
main
函数到底有没有参数?答案是有的。
我们先来看下面运行程序的现象:
#include <stdio.h>
int main(int argc, char* argv[])
{for(int i = 0;i<argc;i++){printf("argv[%d] : %s\n",i,argv[i]);}return 0;
}
这里,我们在命令行中打开某个可执行程序,后面跟上选项(指令 -选项);
可以看到在
main
函数中我们是可以访问命令行输入的内容的(命令行参数)。那
main
函数的参数都有哪些内容呢?
argc
:命令行参数的个数argv
:命令行参数的内容(char*
类型的数组,最后以NULL
结尾)env
:环境变量表(在文章后面内容中详细讲解)。
在这里有一个疑问,我们在命令行输入的内容是如何转化成argv
表,并传递给main
函数的呢?
这个就比较简单了,我们在命令行中输入的内容,由我们的命令行解释器
bash
对这些内容进行拆分,然后形成命令行参数表(argv
)和参数的个数argc
。然后再通过调用等一系列操作(
bash
创建子进程,通过execve
系统调用)将参数传递给main
函数。
简单来说,就是命令行解释器(bash
)对我们命令行内容进行拆分,然后形成命令行参数个数argc
和命令行参数列表argv
。
所以,有了命令行参数列表,我们程序就可以实现不同的子功能(命令 + 选项的实现原理)
环境变量
在了解环境变量之前,先思考一个问题,为什么在执行我们自己写的程序时就要带路径,而使用指令程序时就不用带路径?
我们想要运行一个程序,首先要先找到这个程序(
bash
去找)这个问题就很简单了,我们的指令程序都在
/usr/bin
目录下,而我们的程序不在usr/bin
目录下。但是,为什么在
usr/bin
路径下的程序,在执行时不需要带路径?
- 环境变量一般指操作系统中用来指定操作系统运行环境的一些参数。
- 例如:我们在写的
C/C++
代码,在链接的时候,我们不知道所链接的动静态库在哪里,但是依然可以链接成功生成可执行程序,其原因就是:有关环境变量帮助编译器进行查找。 - 环境变量通常具有某些特殊用途,在操作系统中通常具有全局性
查看环境变量
- 查看所有环境变量:
env
- 查看一个环境变量:
ench $环境变量名
设置环境变量
export
我们现在能够看到环境变量了,我们可不可以修改环境变量?当然是可以的
export
新增环境变量
我们可以使用export
指令来新增一个新的环境变量,具体语法如下:
export name=val
export
除了新增一个环境变量,我们还可以使用它来修改一个已经存在的环境变量的值。
这里如果进行了上述修改,我们的大部分指令都无法使用了,因为在当前PATH
路径下,bash
找不到可执行程序。
但是存在一些还可以使用的指令,因为这些指令是bash
进程自己执行的,比如export
。
在本篇文章后序内容详细叙述
unset
我们可以新增一个环境变量,那我们可不可以删除一个环境变量?当然也是可以的
unset
指令可以删除一个环境变量,用法如下:
unset name
常见的环境变量
PATH
PATH
环境变量,它指的是命令的搜索路径;
为什么在usr/bin
路径下的程序,在执行时不需要带路径?
我们要运行一个程序,首先要找到它,所以我们自己写的程序运行时需要带路径;
而在
usr/bin
路径下的指令程序不需要带路径,这是因为存在环境变量PATH
帮助bash
去查找执行程序。
所以,当我们把我们自己写的程序所在的路径加入到PATH
中,或者将我们的可执行程序放到/usr/bin
目录下,我们运行我们自己写的程序就也不需要带路径了。
这里就不演示了,感兴趣的可以去尝试一下
HOME
在Linux
中,当我们执行cd ~
指令时,我们会进入当前用户的家目录;但是,操作系统是如何知道我们当前用户的家目录呢?
这里就直接说了:存在一个环境变量
HOME
;当我们执行cd ~
时,bash
就会在环境变量表中查找HOME
,然后进行到HOME
加目录中。
此外,root
用户的家目录和普通用户的家目录还是存在一定差别的
SHELL
SHELL
环境变量,它表示当前的shell
,也就是当前使用的命令行解释器;
一般情况下是/bin/bash
。
更多的环境变量
除了上述的环境变量,还存在非常多的环境变量,这里简单了解一下
HOSTNAME
:当前系统的主机名HISTSIZE
:bash
记录历史指令的个数SSH_TTY
:当前通过SSH会话链接终端设备的路径PWD
:表示当前路径USER
:当前用户的登录名LOGNAME
:可以理解为和user
一样_
:表示上次路径
获取环境变量
在上述中,讲述了使用env
和echo $
查看环境变量,那我们现在想要通过写代码时获取环境变量该如何去做呢?
main
函数参数
在上面叙述main
函数参数时,提到main
函数还存在第三个参数env
,我们就可以通过这个参数来获取环境变量
#include <stdio.h>
int main(int argc, char* argv[], char* env[])
{int i = 0;for(;env[i]!=NULL;i++){printf("env[%d] : %s\n",i,env[i]);}return 0;
}
系统调用
main
函数第三个参数env
它是环境变量参数表,我们查看起来不是很方便;
我们可以通过系统调用来在代码中获取环境变量的值:
getenv
getenv
,我们把要查看环境变量的名字传参给getenv
函数,它会返回我们查询环境变量的值。
#include<stdio.h>
#include<stdlib.h>
int main()
{printf("%s\n",getenv("PATH"));return 0;
}
putenv
对于这个函数,这里就先不叙述,在后序文章中再详细讲解。
通过第三方变量获取
在libc
在定义着一个全局变量environ
,它始终指向当前的环境变量表;
它不存在于任何头文件,我们在使用它时,需要使用extern
声明。
#include<stdio.h>
int main(int argc, char* argv[])
{extern char** environ;int i = 0;for(;environ[i]!=NULL;i++){printf("environ[%d] : %s\n",i,environ[i]);}
}
执行程序,我们可以发现依然可以获取全部的环境变量。
此外,父进程的环境变量可以被子进程继承;就比如父进程bash
创建我们的子进程时,
理解环境变量
要理解环境变量,这里我们先思考一个问题,环境变量存储在哪里?
在执行一个程序时,首先要找到到这一个程序,那谁去找呢?
答案是bash
去找,通过环境变量PATH
去找,在bash
中存储着一份环境变量表;
现在又存在一个问题,当我们修改环境变量以后,退出登录,再次登录时我们会发现环境变量又变为修改前的值了。
所以环境变量最开始是存储在哪里呢?
答案:在系统的配置文件中。
那我们现在是不是就可以这样去理解了:在我们每次登录时,操作系统为我们创建一个bash
,再将环境变量表拷贝一份到bash
中;这样我们每次登录bash
中都存在一份环境变量表。
环境变量特性
- 环境变量通常具有全局属性,可以被子进程继承下去。
环境变量表
在上诉代码中,我们无论是使用main
函数参数env
还是全局指针变量environ
进行访问全局变量是时,循环条件写的都是env[i]!=NULL
/environ[i]!=NULL
;
这是因为,环境变量表它本质上就是一个指针数组,数组最后以NULL
结尾。
补充
本地变量
在操作系统中除了环境变量之外,还存在着本地变量;
就比如我们在命令行直接输入i=1
,这样我们使用env
查看环境变量时是查看不到i
的;但是我们可以使用echo $i
来查看变量i
的值。
env
是查看所有的环境变量,而如果我们想要查看所有的本地变量,就要使用set
,它能显示出所有的环境变量和本地变量;当然我们也可以使用echo $
查看某一个变量的值。
这里可能感觉怪怪的,为什么要存在本地变量呢?
- 作用域限制
本地变量仅在当前Shell会话或函数内部有效,不会传递给子进程或其他Shell环境。这种隔离性避免了变量被意外修改或污染其他进程的运行环境。- 临时数据存储
适用于临时存储中间计算结果或循环控制变量(如计数器),用完即弃,无需长期保留,简化资源管理。- 安全性增强
若变量包含敏感信息(如临时密钥),使用本地变量可防止其被子进程继承,降低数据泄露风险。- 避免命名冲突
在脚本或函数中使用本地变量(如通过local
关键字声明),能隔离同名变量的影响,提升代码的模块化和可维护性。
以博主现在的认知,简单理解就是为了满足bash
的语法
内建命令
这个问题在上面简单描述了,我们的环境变量是存在于bash
中的,因为我们所有执行的程序都是bash
去执行的,bash
需要这些环境变量来完成执行我们的程序;
在修改PATH
时,我们发现一个问题,将PATH
修改之后,一部分指令不能执行了,但是一部分指令是可以执行的,这是为什么呢?
这里简单解释一下:
我们可以将指令分为两部分:
- 普通命令:
bash
通过创建子进程,然后让子进程去执行;- 内建命令:
bash
自己通过函数调用或者系统调用去完成,不需要创建子进程。
这里内建命令像export
就是bash
自己直接去完成的,我们就是修改了PATH
对它是没有影响的,所以它可以执行;
到这里本篇文章内容大致就结束了,感谢支持
简单总结:
- 了解命令行参数,理解
main
函数是三个参数- 环境变量,查看
env/echo
、设置环境变量export
- 了解常见的环境变量
- 通过
main
函数参数、系统调用、environ
获取环境变量- 理解环境变量具有全局性、环境变量表的结构
- 简单了解本地变量和内建命令