文章目录
- 一、命令行参数
-
- [1. main 函数参数](#1. main 函数参数)
- [2. 如何理解命令行参数](#2. 如何理解命令行参数)
- 二、环境变量
-
- [1. 基本概念](#1. 基本概念)
- [2. 常见环境变量](#2. 常见环境变量)
- [3. 查看环境变量方法](#3. 查看环境变量方法)
-
- [3.1 测试 PATH](#3.1 测试 PATH)
- [3.2 测试 HOME](#3.2 测试 HOME)
- [4. 和环境变量相关的命令](#4. 和环境变量相关的命令)
- [5. 环境变量的组织方式](#5. 环境变量的组织方式)
- [6. 获取环境变量](#6. 获取环境变量)
-
- [6.1 命令行第三个参数](#6.1 命令行第三个参数)
- [6.2 通过系统调用获取](#6.2 通过系统调用获取)
- [6.3 第三方变量 environ](#6.3 第三方变量 environ)
- [7. 本地变量](#7. 本地变量)
- 总结
一、命令行参数
1. main 函数参数
在我们一开始学习 C C C 语言的时候, m a i n main main 函数一直都是作为函数的入口,而在实际代码的运行中, m a i n main main 也会被其他函数所调用,其有两个参数: a r g c argc argc 和 a r g v argv argv。
c
#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;
}
-
a r g c argc argc:表示 a r g v argv argv 数组的元素个数。
-
a r g v argv argv:一个变长的字符指针数组,用来存放运行时的命令行参数(以空格为分隔符),并且以 N U L L NULL NULL 结尾。

2. 如何理解命令行参数
m a i n main main 命令行参数:是运行同一个命令,可以通过不同的选项,来实现不同的子功能的方法!(指令选项的实现方法)
c
#include <stdio.h>
#include <string.h>
int main(int argc, char* argv[])
{
if(argc != 2)
{
printf("Usage:%s [-a/-b/-c]\n", argv[0]);
return 1;
}
const char* arg = argv[1];
if(strcmp(arg, "-a") == 0)
printf("这是功能1\n");
else if(strcmp(arg, "-b") == 0)
printf("这是功能2\n");
else if(strcmp(arg, "-c") == 0)
printf("这是功能3\n");
else
printf("Usage:%s [-a/-b/-c]\n", argv[0]);
return 0;
}

因此,每个进程都会拥有一张 a r g v argv argv 表,用来支持实现选项功能!
二、环境变量
要执行一个程序,必须先找到它!我们自己实现的二进制程序需要带有
./
才能运行(表示当前路径),而系统提供的指令却不需要,这是为什么?
实际上,在系统中, b a s h bash bash 会通过环境变量 P A T H PATH PATH(系统中搜索指令的默认搜索路径),来帮助系统找到目标二进制文件!

1. 基本概念
环境变量( e n v i r o n m e n t v a r i a b l e s environment\ variables environment variables)一般是指在操作系统中用来指定操作系统运行环境 的一些参数 (被 b a s h bash bash 使用,即用户间接使用)。其通常具有某些特殊用途,还有在系统当中通常具有全局特性。
如:我们在编写 C / C C/C C/C++ 代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
2. 常见环境变量
环境变量 | 内容 |
---|---|
P A T H PATH PATH | 指令 / / /命令的搜索路径 |
H O M E HOME HOME | 当前用户的家目录 ~ (即用户登录到 L i n u x Linux Linux 系统时的默认目录) |
S H E L L SHELL SHELL | 当前 s h e l l shell shell,它的值通常是 /bin/bash |
U S E R USER USER | 当前用户名 |
L O G N A M E LOGNAME LOGNAME | 登陆时的用户名 |
H I S T S I Z E HISTSIZE HISTSIZE | 保存的历史命令的数量 |
H O S T N A M E HOSTNAME HOSTNAME | 当前主机的主机名 |
P W D PWD PWD | 当前 s h e l l shell shell 所在的路径 |
O L D P W D OLDPWD OLDPWD | s h e l l shell shell 上一次所在的路径 |
3. 查看环境变量方法
命令:
echo $[环境变量名称]
。

其中,这里路径都是绝对路径 。多个路径之间以 : : : 分割,如果前一个路径没有找到,将会继续在下一个路径寻找,如果都没有找到,则说明该命令不存在。
3.1 测试 PATH
添加环境变量,不仅可以将命令拷贝到系统路径下,还可以将该命令的所在路径添加到 P A T H PATH PATH 路径。
PATH=[要添加的路径]
:会将 P A T H PATH PATH 之前的路径也一同覆盖掉。

PATH=$PATH:[要添加的路径]
:追加路径,不会覆盖。

注意:添加的环境变量不是永久的,当断开连接或者重新打开终端时,环境变量会自动恢复默认!
3.2 测试 HOME
H O M E HOME HOME 环境变量,是当前用户的家目录(
~
)。

由于是存放的当前用户的家目录,因此 r o o t root root 用户的 H O M E HOME HOME 环境变量自然也是 /root
目录:

4. 和环境变量相关的命令
命令 | 作用 |
---|---|
e c h o echo echo | 显示某个环境变量值 |
e x p o r t export export | 设置一个新的环境变量 |
e n v env env | 显示所有环境变量 |
u n s e t unset unset | 清除环境变量 |
s e t set set | 显示本地定义的 s h e l l shell shell 变量和环境变量 |
5. 环境变量的组织方式
每个程序都会收到一张环境变量表:环境变量表是一个字符指针数组,每个指针指向⼀个以
'\0'
结尾的环境字符串。因此,环境变量就是一个 k e y = v a l u e key=value key=value 的字符串。

在我们在命令行输入命令时, b a s h bash bash(内部存储了两张表)会获取到我们的命令行参数,然后先构建命令行参数表 ,再根据命令找到环境变量表 中的 P A T H PATH PATH,然后根据其中的路径寻找,如果找到,就创建进程执行。
那么环境变量最开始在哪里呢? ------ ------ ------ 在系统的相关配置文件中!
在家目录下,有两个 b a s h bash bash 默认配置文件:
总结一下,环境变量的生命周期是由 b a s h bash bash 决定的:
-
在登录的时候, b a s h bash bash 会根据环境变量配置文件来创建环境变量表,在 b a s h bash bash 运行期间,修改的环境变量其实是修改的 b a s h bash bash 里存放的环境变量表,在退出的时候, b a s h bash bash 回收,空间释放。等到再次登陆,又会重新根据配置文件重新创建新的环境变量表,因此之前修改过的表就会丢失。
-
如果修改了环境变量配置文件,对当前运行的 b a s h bash bash 中的环境变量表并无影响(因为其在修改前就已经创建),但等到 b a s h bash bash 退出,再次登陆时, b a s h bash bash 就会依据修改过的配置文件来创建新的环境变量表,进而在以后的每一次登陆,环境变量都会修改,从而达到永久修改的目的。
6. 获取环境变量
6.1 命令行第三个参数
m a i n main main 函数的第三个参数 e n v env env:一个变长的字符指针数组,用来存放环境变量,并且也以 N U L L NULL NULL 结尾。
c
#include <stdio.h>
int main(int argc, char* argv[], char* env[])
{
(void)argc;
(void)argv;
for(int i = 0; env[i]; i ++) // 当 env[i] == NULL 时,循环结束
{
printf("env[%d]-> %s\n", i, env[i]);
}
return 0;
}
可以看到,获取到了所有的环境变量:

环境变量有什么特性呢? ------ ------ ------ 环境变量通常具有全局属性,可以被子进程继承下去。
-
环境变量是由父进程( b a s h bash bash)获取。
-
环境变量可以被子进程继承。(全局特性)
6.2 通过系统调用获取
常用 g e t e n v getenv getenv 和 p u t e n v putenv putenv 函数来访问指定的环境变量。

c
#include <stdio.h>
#include <stdlib.h>
int main()
{
char* value = getenv("PATH"); // 获取PATH环境变量的内容
if(value == NULL)
return 1;
printf("PATH->%s\n", value);
return 0;
}

小应用 ------ 只针对特定用户才能使用的代码逻辑:
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
const char* who = getenv("USER");
if(who == NULL)
return 1;
if(strcmp(who, "ybc") == 0)
{
printf("程序正常运行逻辑!\n");
}
else
{
printf("Only ybc!!\n");
}
return 0;
}

为什么环境变量可以被子进程继承呢?
-
子进程可以根据环境变量来进行个性化操作(如上述,定制一个只能由自己执行的程序)。
-
可以通过环境变量来进行进程级别的数据传递,进而可以实现对子进程的控制逻辑。
6.3 第三方变量 environ
在 l i b c libc libc 中定义的全局变量 e n v i r o n environ environ 指向环境变量表。由于 e n v i r o n environ environ 没有包含在任何头文件中,所以在使用时,要用 e x t e r n extern extern 声明。

c
#include <stdio.h>
extern char** environ; // 声明全局变量
int main()
{
for(int i = 0; environ[i]; i ++) // 当 environ[i] == NULL 时,循环结束
{
printf("environ[%d]-> %s\n", i, environ[i]);
}
return 0;
}
7. 本地变量
我们可以在 s h e l l shell shell 命令行中自定义本地变量,其不会被子进程继承,只能在 b a s h bash bash 内部有效。
b a s h bash bash 会记录两套变量:
- 环境变量:可以通过
env
命令来查看所有环境变量。 - 本地变量:可以通过
set
命令来查看所有本地和环境变量。
由于 b a s h bash bash 内部需要支持 s h e l l shell shell 脚本(一种脚本语言),因此需要支持本地变量。

也可以利用 export
命令将本地变量导入到环境变量:

我们导入的环境变量在谁里面?
导入在 b a s h bash bash 里面!
为什么 e x p o r t export export(子进程)能把环境变量给 b a s h bash bash(父进程)呢?
因为 e x p o r t export export 是内建命令 ( b u i l t − i n c o m m a n d built-in\ command built−in command):其不需要创建子进程,而是让 b a s h bash bash 自己调用函数执行,或者系统调用完成!也就是说,只要 b a s h bash bash 能够运行,内建命令就能够运行。
总结
环境变量是操作系统特定的一些全局变量,其通常有特定的用途,用来记录系统相关的信息,比如:主机名、家目录的路径、当前命令行的路径、命令的搜索路径等等。这些环境变量都能够被子进程继承,因此类似 g c c gcc gcc、 g g g++ 等工具也能继承,从而可以通过环境变量找到动静态库来进行链接。