008-Linux命令行参数和环境变量

Linux命令行参数和环境变量

1. 命令行参数

1.1 引出问题

我们学习C语言的时候,写main函数的时候一般都是没有带参数的,但是main函数既然是一个函数,也是被调用的,按理来说也能和其他函数一样,也能带参。

事实也是如此,main函数是可以带参数的,但是并不是随意带的,而是以这种格式来带的int main(int argc, char *argv[])

但是这些参数又是什么意思??

  • char *argv[]是一个char指针数组,这个数组中的每一个char*指针都分别指向一个字符串。
  • int argc是一个整数,代表argv中元素的个数。

1.2 测试

我们使用一个简单的代码来测试一下这些指针分别指向什么字符串:

Linux命令行参数和环境变量

1. 命令行参数

1.1 引出问题

我们学习C语言的时候,写main函数的时候一般都是没有带参数的,但是main函数既然是一个函数,也是被调用的,按理来说也能和其他函数一样,也能带参。

事实也是如此,main函数是可以带参数的,但是并不是随意带的,而是以这种格式来带的int main(int argc, char *argv[])

但是这些参数又是什么意思??

  • char *argv[]是一个char指针数组,这个数组中的每一个char*指针都分别指向一个字符串。
  • int argc是一个整数,代表argv中元素的个数。

1.2 测试

我们使用一个简单的代码来测试一下这些指针分别指向什么字符串:

运行:

通过上面的测试,我们可以很容易发现,argv[]里面的指针指向的字符串,就是我们在命令行中运行这个程序时输入的参数,其中第一个字符串代表程序的路径+名称(./xxxxx),后面的参数代表我们运行程序时输入的选项,以空格作为分隔符。

在argv数组中,实际上是有argc个元素的,最后一个元素指向NULL,我们可以修改一下代码进行测试:

1.3 作用

这个功能有什么意义呢,这时我们想想,我们之前使用的Linux命令,比如:ls、cd、cp、mv......我们在使用这些指令的时候,都是可以带参数的,有些指令带不同的参数就会有不同的功能,我们之前说过,我们使用的这些指令本质上就是一个个可执行文件,那么我们也就可以像这些指令一样,编写我们自己的程序,通过命令行参数来实现,输入不同的选项,就可以实现不同的功能。

1.4 原理

我们之前说过,我们在命令行中启动的进程的父进程都是bash,而且之前说过,子进程在被创建的时候,继承的是父进程的代码和数据,而我们在命令行中输入的东西,都是给bash的,而bash是命令行解释器,它会解释我们输入的字符串,处理好,然后执行。所以我们输入的这些参数,实际上是由bash构建成了一张表,然后继承给子进程,子进程自然也就能读取到父进程中的表的内容。

2. 环境变量

2.1 引出问题

我们使用的自己写的程序都需要带路径来执行,但是使用Linux指令时为什么可以不带路径直接使用?Linux指令本质上不也是程序吗??

原因是,Linux系统中存在一些全局的设置,用来告诉命令行解释器,应该去哪个路径下去查找这个命令。

而这个全局的设置就是环境变量

2.2 查看环境变量

PATH就是环境变量的其中一个,我们可以通过echo $PATH来查看PATH的内容(类似于PATH这种大写的就是环境变量,查看环境变量的内容需要在环境变量的名字前面加上$符号):

这个配置,在我们登录Linux系统时,就从配置文件中加载到bash进程中的(内存中)。

其中这里面的内容是一个个路径,以:分隔,bash在执行命令时,会先在这些路径下搜索命令,从第一个开始找,找到了就执行,如果没找到,就会提示没有找到该命令,我们使用的Linux指令(如ls、cd......)基本都是在/usr/bin路径中的,所以我们在执行这些命令时,bash就会到PATH中的路径去找命令,然后再/usr/bin路径下找到命令,然后执行。

2.3 修改环境变量

测试代码:

那么我们是否可以让我们执行自己的程序像执行系统指令一样,无需带上路径?

当然是可以的:

  • 方法一:将我们的程序拷贝到当前已有的环境变量的路径下(不推荐)。

  • 方法二:将当前路径添加到PATH中(PATH=$PATH:我们的路径)。

    但是,上面说过PATH是在我们登录时从配置文件中加载到内存里的,所以我们当前修改只是内存级的,如果我们退出再登录,这个配置就不在了。

  • 方法三:修改配置文件(~/.bash_profile)。

    先看看这个文件:

    我们可以看到,这里面不就是我们的PATH吗?此时,我们添加路径只需要添加到PATH那一行的后面:

    然后重新登录,我们就会发现,PATH中就自动加载了我们对应的路径:

2.4 其他环境变量

环境变量并不是只有PATH,PATH只是众多环境变量的一种,我们可以使用env命令查看所有环境变量:

我们介绍其中几个环境变量:

  • HOME:这个环境变量就是我们当前用户的家目录

  • PWD:就是我们当前所处的路径(动态变化)

  • SHELL:bash所处的路径

  • HISTSIZE:系统默认记录用户最新使用的命令的数量(我们可以history查看我们的历史命令)

  • HOSTNAME:我们的主机名

  • LANG:当前编码方式

2.5 自定义环境变量

2.5.1 添加环境变量
复制代码
export 环境变量名=环境变量值

内存级添加,后续登录就没了。

【注意】如果不添加export,直接使用环境变量名=环境变量值,添加的是本地变量。

2.5.2 删除环境变量
复制代码
unset 环境变量名

内存级删除,不影响后面的登录。

2.6 整体理解环境变量、系统

2.6.1 C语言获取环境变量

在系统中存在一个全局变量environ,这个环境变量是一个二级指针。

这个二级指针指向的东西就是一个个一级指针,而每个一级指针又指向一个字符串,每个字符串就是一个环境变量,environ指向的最后一个一级指针是NULL代表结束(像极了前面的argv)。

(其中的的一些其他)

【注意】使用environ之前,需要先使用extern声明。

测试代码:

这个和我们刚刚使用env查到的环境变量是一模一样的。

这个和命令行参数类似,在bash启动的时候,从配置文件中加载到自己的数据中,然后,我们使用命令行运行程序的时候,程序也就继承了bash的数据,也就能看到bash加载的环境变量。

实际上,我们的main函数也是可以有第三个参数的。

我们也可以通过这种方式来获取环境变量。

有了上面的环境变量表,我们就可以理解,前面使用export导入环境变量实际上就是在env表上加上一条数据。

我们不仅可以通过上面的方式来获取全部的环境变量,也能通过getenv来获取指定的环境变量。

【总结】代码获取环境变量的三种方式:

  • 通过全局变量environ获取
  • 通过main函数参数env获取
  • 通过getenv函数获取
2.6.2 理解

我们所有运行的程序,都是在bash下运行的,也就是所有的进程都是bash的子进程,自然这些子进程也就能继承bash的数据。

因此,环境变量具有系统级的全局属性,因为环境变量本身会被子进程继承下去。

这里还有一个问题:我们使用export添加环境变量也是命令,按理来说也是创建子进程来完成的,既然如此,子进程中修改的数据怎么可以被父进程看到???

其实实际上有一小部分命令不是由bash创建子进程来完成的,而是bash自己完成的,比如export、echo......像这样由bash亲自执行的命令就叫做内建命令

如何判断哪些命令是内建命令?将PATH置为空,还能运行的命令就是内建命令,也就是不需要找到程序去运行的命令,就是内建命令。

上面说的本地变量,使用env是查不到的,同样,在代码中使用getenv函数也是查不到的,但是我们通过echo可以将这个变量的内容打印出来,说明这个变量是存在的,只是没有被放到env表中,我们也可以通过export 本地变量命令将本地变量导入到env表中(本地变量只在bash内部有效,无法被子进程继承下去,所以子进程无法查到,echo能看到,所以echo是内建命令)。

相关推荐
何中应2 小时前
虚拟机内的系统无法解析外网域名
linux·运维·后端
红叶尽染寂绀蓝2 小时前
已解决:同一ip下,Mac和Windows同时用vscode连接某个Linux远程服务器后,Mac再次连接时无法正确打开远程文件夹,由于转发设置导致
linux·服务器·windows·vscode·tcp/ip·macos
哈哈浩丶2 小时前
LK(little kernel)2:官方LK的通用启动流程
linux·驱动开发
_OP_CHEN2 小时前
【Linux系统编程】(三十四)初识进程信号:Linux 软中断的核心奥秘
linux·后端·操作系统·进程·信号·终端信号
盟接之桥2 小时前
盟接之桥说制造:制造业的精致之道,致制造人
大数据·linux·运维·人工智能·windows·安全·制造
夏乌_Wx2 小时前
从零开始实现一个自己的 Shell:mybash 项目实战
linux·c语言·后端
Codefengfeng12 小时前
CTF工具篇
linux·运维·服务器
上海合宙LuatOS12 小时前
LuatOS核心库API——【i2c】I2C 操作
linux·运维·单片机·嵌入式硬件·物联网·计算机外设·硬件工程