linux系统之----命令行参数和环境变量
一、命令行参数
1.main()函数的参数
在C语言中,main
函数可以接收命令行参数,其标准形式为:
int main(int argc, char *argv[]) {// 程序代码return 0;
}
这里我们解释一下:
argc
:参数个数计数器(Argument Count),表示命令行参数的个数,包括程序名称本身。它是一个整数,值至少为1(因为程序名称本身算一个参数)。
argv
:参数值数组(Argument Vector),是一个指向字符数组的指针数组,每个元素指向一个以null结尾的字符串,这些字符串就是命令行参数。argv[0]
通常是程序的名称,argv[1]
到argv[argc - 1]
是用户提供的参数,argv[argc]
为NULL
。换句话说,argv的最后一个一定是NULL,其余的元素由用户指定!
代码测试:
假设我们创建一个文件demo.c,并写入如下内容:
#include <stdio.h>int main(int argc, char *argv[]) {printf("参数个数:argc = %d\n", argc);printf("程序名称:argv[0] = %s\n", argv[0]);for (int i = 1; i < argc; i++) {printf("参数 %d:argv[%d] = %s\n", i, i, argv[i]);}return 0;
}
写完之后保存并编译,并对上文内容进行测试,如下图所示:
倘若我们多试几个参数呢?
再测试一组:
由此可见,argv[i]为什么是根据用户的空格分开的内容决定的。
最后三句话总结:
1.命令行参数,至少一个
2.进程对应的程序的名字,一般是argv[0]
3.有几个字串,argc就是几,记得用空格隔开
2. 设计这个东西有什么用?
命令行参数让程序可以根据用户输入的参数灵活地执行不同的操作,增强了程序的通用性和灵活性。例如,不同的参数可以触发程序的不同功能。
根据参数执行不同功能
我们看如下代码:
#include <stdio.h>
#include <string.h>int main(int argc, char *argv[]) {if (argc != 2) {printf("usage wrong!用法: %s <参数>\n", argv[0]);return 1;}if (strcmp(argv[1], "start") == 0) {printf("开始任务...\n");} else if (strcmp(argv[1], "stop") == 0) {printf("停止任务...\n");} else if (strcmp(argv[1], "status") == 0) {printf("任务状态: 运行中\n");} else {printf("未知参数: %s\n", argv[1]);}return 0;
}
我们将其保存并编译一下,并进行代码测试:
那么好了,今天我写的是简易的代码,就输出的是字符串,那明天我能不能就把linux指令按照此例复刻出来呢?例如-l -a等等, 那换句话说,我们之前学的一些Linux指令本质就是一段程序,而我们-l -a 等等这些选项,究其本质,就是一个一个的字符串,可以以一定的方式传递给你ls内部的main,在ls内部实现的时候,就可以根据不同的选项,实现类似功能的不同表现形式。
二、环境变量
1.定义:
是系统级别的全局变量,具备不同的用途
2.常见的环境变量
2.1 PATH
作用:用于定义系统查找可执行文件的路径。它是一个由冒号分隔的路径列表,系统会按照这个顺序在这些路径中查找命令的可执行文件。
所以说,操作系统查找可执行命令,是在环境变量 PATH中查找的,如何证明呢?
我们发现ls在路径usr/bin下,而echo &PATH包含这一路径,由此得以证明
2.2 HOME
作用:指定当前用户的主目录路径。对于用户名为 username
的用户,HOME
的值通常是 /home/username
。
2.3 SHELL
作用:指定当前用户使用的 shell 程序的路径。
2.4 找不到可执行程序
三、获取环境变量
1.通过 main 函数获取环境变量
实际上,main函数是有三个参数的,其原型如下:
int main(int argc, char *argv[], char *envp[])
前两个参数解释过了,不再解释了,这里仅解释第三个参数:
envp
:是一个指向字符串数组的指针,说白了是个指针数组,数组里面存的一堆指针,这些字符串是环境变量,每个环境变量的格式为 KEY=VALUE
。
1.1 环境变量表
我们输入env,之后会弹出来一坨东西,(可能一瞬间有点绝望哈),好,我们看如下几个参数:
这里我就按照老师的板书截出来了一部分,好奇的可以自己试一下去,命令env就是看环境变量的意思。
好,现在我们回到环境变量表上,我们main函数的第三个参数指向就是这个环境变量表,那这个环境变量表到底长什么样子呢?
环境变量表的结构
字符串数组形式:环境变量表本质上是一个字符串数组,每个字符串表示一个环境变量,格式为 KEY=VALUE
。例如,PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
,其中 PATH
是键,/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
是值。
以NULL结尾:环境变量表以空指针(NULL)结尾,表示表的结束。在 C 语言中,可以通过遍历这个数组直到遇到 NULL 来获取所有的环境变量。
借用一下老师的板图,具体感受一下:
用东北话讲就是一个萝卜一个坑,每个萝卜都是K=V的结构,最后一个坑啥也不种。
2、通过函数获取单个环境变量
可以使用 getenv()
函数来获取单个环境变量的值:
我们输入man 3 getenv,得到如下内容(部分):
说明:
name
:是要获取的环境变量的名称。
返回值:如果找到该环境变量,则返回一个指向其值的指针;如果没有找到,则返回 NULL
代码示例:
#include <stdio.h>
#include <stdlib.h>int main() {char *path = getenv("PATH");if (path != NULL) {printf("PATH: %s\n", path);} else {printf("PATH not found\n");}return 0;
}
大家可以在xshell上自己试一下!感受一下~
代码运行结果
我们把那个PATH改一下改成PAHT看看结果
显示路径不存在!
环境变量查看实验成功!
3.通过 environ
获取所有环境变量
在 C 语言中,可以通过 extern char **environ
来访问所有的环境变量:
#include <unistd.h>extern char **environ;
environ
是一个指向字符串数组的指针,这些字符串是环境变量,每个环境变量的格式为 KEY=VALUE
。
#include <stdio.h>
#include <unistd.h>extern char **environ;int main() {for (char **env = environ; *env != NULL; env++) {printf("%s\n", *env);}return 0;
}
编译测试一下:
结果得到如下的一大堆:
不要怕~这就是我们要查找的 所有环境变量
查找成功!
4.环境变量的获得
实际上,我们运行程序或者进程时,并不是我的进程获得了环境变量,而是我的父进程(bash!!!)获得了环境变量,形成了上文所示的环境变量表,而我们的子进程是会继承父进程的代码和数据!例如,当你在终端中启动一个程序时,该程序会继承终端进程的环境变量。
那么bash又是哪里来的环境变量呢?答案是从系统的配置文件中来!大家如果学习过ros在配置humble环境的时候应该频繁输入过bash或者bashrc等等诸如此类的代码,实际上就是在配置环境!
不信的话,大家可以做一下~/.bash_profile && ~/.bashrc来修改文件级环境变量
5. 为什么要有环境变量
答案是不同的环境变量,会有不同的用途!!!
如果我想写一个只有自己能执行的可执行程序呢?这个问题我们先保留。
大家还记得pwd命令是什么吗?是用于显示当前工作目录的路径的,那是怎么显示的呢?
实际上,进程会记录自己的工作路径(current working directory, cwd)。在 Linux 系统中,每个进程都有一个 task_struct
结构,其中保存了进程的 cwd。当创建子进程时,子进程会继承父进程的 task_struct
,因此子进程的 cwd 与父进程相同。在 Bash shell 中,PWD
环境变量也会保存当前工作目录的路径。Bash 的 pwd
命令会从 PWD
环境变量中获取当前目录信息。
所以说,我们的父进程bash的cwd也在task_struct里面保存着,我们的子进程自然而然的就继承了这个task_struct,所以说,我自己的pwd从哪里来?还是从bash来的!!
那么,bash的pwd从哪里来呢
5.1 getcwd函数
getcwd
函数:
作用:用于获取当前工作目录的路径。
函数原型:(输入man 3 getcwd获得)
我们看如下代码:
#include <unistd.h>
#include <stdio.h>int main() {char pwdbuf[128];char *pwd = getcwd(pwdbuf, sizeof(pwdbuf));printf("%s\n", pwd);return 0;
}
编译并运行一下,查看结果:
对比一下:
因此,说明了getcwd 是用于获取当前工作目录的路径。换句话讲,bash的pwd也是通过getcwd函数获得的!
四、环境变量的特点和总结
1.环境变量的来源
大部分环境变量来自系统的配置文件(如 /etc/profile
、/etc/environment
)和用户的配置文件(如 ~/.bashrc
、~/.bash_profile
)。少部分环境变量是启动后动态获取或创建的,例如 PWD
环境变量会在进程工作目录改变时动态更新。
2. 环境变量的全局性
环境变量具有全局属性,对当前进程及其所有子进程都有效。例如,在 Bash shell 中设置的环境变量会传递给通过该 shell 启动的所有子进程。
但是,本地变量(local variable)只在父进程(如 Bash shell)内部有效,不会传递给子进程。
传递不了,没有结果显示
或者看这个例子也行,找出来那么多带“me"的进程,但是就是没有我要的那个”me"进程
3.环境变量的动态性
环境变量可以在运行时动态修改。例如,使用 export
命令可以临时修改环境变量。
修改环境变量后,子进程会继承修改后的值。
3.1 export详细解释
1.基本概念
在 Linux/Unix 系统中,export
是 shell 的一个内置命令,用于将变量或函数设置为环境变量。这意味着这些变量或函数不仅在当前 shell 会话中可用,还会被传递给其子进程。
2.语法
export [选项] [变量名=[值]]
3.export
的选项
-f
:用于导出函数。
-n
:用于取消导出变量或函数。
4.使用 export
出变量
导出简单变量
我们在xshell上面依次输入如下内容,观察现象:
# 设置一个局部变量
MY_VAR="Hello World"# 打印局部变量
echo "In parent shell: $MY_VAR" # 输出:In parent shell: Hello World# 启动一个子 shell,并尝试访问该变量
bash -c 'echo "In child shell: $MY_VAR"' # 输出:In child shell:# 使用 export 将变量导出为环境变量
export MY_VAR# 再次启动一个子 shell,并访问该变量
bash -c 'echo "In child shell: $MY_VAR"' # 输出:In child shell: Hello World
运行结果正确:
在这个例子中,MY_VAR
最初是一个局部变量,仅在父 shell 中可用。使用 export
后,它变成了环境变量,子 shell 也可以访问它。说白了,就是把它给升级了,可以理解为export就是专升本考试,没export,只能在父进程里面用,export以后,升级了,子进程也可以用了! (个人观点,有不当之处可以评论区指出!)
4.总结
环境变量是系统和应用程序配置的重要组成部分,用于存储运行时需要的配置信息。
环境变量可以通过多种方法获取,包括通过 main
函数的参数、getenv
函数和 environ
变量。
环境变量具有全局性和动态性,可以在进程及其子进程中使用和修改。
环境变量的初始化主要通过系统和用户的配置文件完成,少部分变量会在运行时动态获取或创建。
五、内建命令
1.定义
内建命令(built-in command)是直接在 shell(如 Bash)内部实现的命令,而不是作为单独的可执行文件存在。它们是 shell 的一部分,因此执行时不需要创建新的子进程
2、内建命令的特点
执行效率高:由于内建命令在 shell 内部执行,不需要创建新的进程,因此执行速度更快。(不能创建子进程)
可以直接访问和修改 shell 的内部状态:内建命令可以直接操作 shell 的环境变量、选项和其他内部状态。
不需要子进程:内建命令在当前 shell 中执行,不会创建新的子进程。
3.内建命令与普通命令的区别
普通命令:大多数命令是可执行程序,存储在文件系统中(如 /bin
、/usr/bin
等目录)。执行时,shell 会创建一个新的子进程来运行这些命令。例如,ls
、grep
等。
内建命令:内建命令是 shell 内置的,直接在当前 shell 中执行。例如,cd
、export
、echo
等。
4.内建命令的示例
1. echo
命令
echo
是一个内建命令,用于输出文本或变量的值。
在这个例子中,echo
直接在当前 shell 中执行,能够访问当前 shell 的环境变量 MYENV
。
2. cd
命令
cd
是一个内建命令,用于更改当前工作目录。
3.其他命令
实际上这样的命令还有很多,在这里我帮大家找了一些,大家可以看一看
5、内建命令的执行机制
当你在 shell 中输入命令时,shell 会先检查该命令是否为内建命令。如果是内建命令,shell 会直接在当前进程中执行它;如果不是内建命令,shell 会尝试在 PATH
环境变量指定的路径中查找可执行文件,并创建一个新的子进程来运行它。