一、命令行参数

1. 什么是命令行参数?

在Linux终端中,执行可执行程序时,在程序名称后方追加的自定义参数,统称为命令行参数

示例:./code a b c,其中 ./code 是可执行程序,a、b、c 就是传给程序的命令行参数。该机制允许程序在运行阶段接收外部数据,无需修改代码重新编译,极大提升程序灵活性。

2. C语言获取命令行参数

我们日常写的无参 main 函数是简化写法,C语言标准的 main 函数自带三个参数,专门用于接收命令行参数,定义如下:

int main(int argc, char *argv[], char *env[]);

2.1 核心参数功能详解

  • argc(argument count):整型参数,代表命令行参数的个数,统计包含程序名在内的所有参数总数。

  • argv(argument vector):字符指针数组,存储所有命令行参数字符串,每一个数组元素指向一个参数字符串。

  • env:环境变量指针数组,本文第二部分详细讲解。

3. 代码实操演示

3.1 测试代码


3.2 运行结果


4. 原理解析

执行指令" ./code a b c ss   aa  ww -- "时,系统会自动拆分参数:参数总数 argc=8argv[0] 固定存储程序本身路径及名称,后续下标依次存储自定义参数。

本质:终端输入的整行指令,会被bash以空格为分隔符拆分字符串,存入 argv 数组,供程序读取使用。

5. 使用场景

  • 简易配置:程序运行时传入标记(如开启调试模式、设置运行权限);

  • 批量处理:传入多个文件路径,批量读写操作文件;

  • 指令开发:Linux自带指令(ls、cp、mv)都依赖命令行参数,如 ls -l

二、环境变量

1. 前置疑问:为什么自己写的程序要加 ./ ?

常见疑惑:系统命令lsmkdirpwd 可以直接输入执行,而自己编译的 code 必须写 ./code,直接输入code 会提示命令不存在。

1.1 核心原因

Linux终端(bash)执行指令时,不会全盘扫描磁盘,而是按照PATH环境变量记录的路径顺序,依次查找可执行文件:

  • 系统命令:存放于PATH默认配置的系统目录(/bin/usr/bin),bash可自动检索;

  • 自定义程序:存放在当前工作目录,默认不在PATH路径中,bash检索不到,必须手动加路径 ./(当前目录)指定位置。

2. PATH环境变量详解

PATH 是Linux最重要的环境变量,作用:存储系统指令搜索路径,多个路径用冒号 : 分隔。

查看PATH指令:echo $PATH

2.1 错误修改PATH:直接赋值

错误写法

PATH=/...路径

问题剖析
  1. 该修改方式定义的是本地shell变量,不是环境变量;

  2. 使用 env 指令无法查询到该变量,仅能用 echo $PATH 临时查看;

  3. 直接赋值会覆盖原有PATH所有系统路径,导致 ls、mkdir 等系统命令全部失效。

2.2 正确修改PATH:追加路径

正确写法

PATH=$PATH:/...路径


语法解析
  • $PATH:引用原有PATH所有路径,保留系统命令检索目录;

  • ::路径分隔符,追加自定义程序路径。

修改完成后,无需加 ./,直接输入 code 即可运行自定义程序,同时保留ls等系统命令。

3. PATH修改的关键特性

3.1 临时生效(内存级修改)

无论正误修改方式,终端中直接修改的PATH仅保存在内存中,属于临时修改。一旦关闭当前终端、重新连接Linux,PATH会自动还原为系统默认配置,不会永久篡改系统文件。

3.2 误修改补救方案

若错误赋值导致ls等命令失效,无需手动还原路径,直接关闭当前终端,重新打开即可。bash重启后会自动读取系统配置文件,重置PATH为默认值。

4. 常见环境变量与操作指令

4.1 常见环境变量

  • HOME:当前用户家目录,普通用户默认 /home/用户名,root用户 /root

  • SHELL:当前终端解析器,默认 /bin/bash

  • HOSTNAME:主机名称。

  • USER: 当前用户名

  • PWD: 当前路径

4.2 环境变量常用指令

  • echo $变量名:打印指定环境变量,示例 echo $HOME

  • env:查看系统所有环境变量;

  • export:设置一个新的环境变量;

  • unset 变量名:删除环境变量。

  • set: 显⽰本地定义的shell变量和环境变量;

5. 代码获取环境变量

在C语言中,Linux下一共有三种标准方式获取环境变量,分别是:main函数第三个env参数、全局变量environ、库函数getenv。下面全部实操演示,并对比三者区别,补齐知识点。

5.1 方式一:通过main()函数第三个参数 env 获取

main函数完整原型:int main(int argc, char *argv[], char *env[]);env 是字符指针数组,专门存储全部环境变量,以NULL作为数组结束标志。


5.2 方式二:通过全局变量 environ 获取

Linux系统在libc库中定义了全局外部变量 environ,同样是环境变量指针数组。该变量没有头文件声明,使用必须手动 extern 声明。


5.3 方式三:通过系统函数 getenv() 获取(推荐)

前两种方式都是遍历全部环境变量,而 getenv() 可以精准获取指定名称的环境变量,使用最简单、开发最常用。


5.4 三种方式优缺点对比

获取方式

特点

优缺点

使用场景

main函数env参数

程序启动自动接收

优点:无需额外声明;缺点:只能全部遍历,无法精准查找

查看全部环境变量

全局变量environ

libc全局外部变量

优点:不受main参数限制;缺点:需要extern声明,遍历繁琐

底层遍历、内核源码开发

getenv()函数

标准库函数

优点:精准查询、代码简洁、安全稳定;缺点:一次只能查一个

日常开发首选

6. 深层剖析:环境变量是谁给的?为什么程序可以获取?

当我写完三种获取代码后会产生疑问:环境变量到底是谁提供的?为什么我们写的C程序可以直接读取?数据从哪来?本节结合Linux进程底层原理,直白通俗解答。

6.1 谁给的环境变量?

最终来源:bash终端(父进程)

  • 我们在Linux操作的终端,本质是一个 bash进程

  • 系统开机登录用户时,bash会自动读取系统配置文件,加载默认环境变量(PATH、HOME、USER等);

  • 我们手动使用 export 创建的环境变量,也是写入当前bash进程内部;

  • 我们运行的C语言程序,是bash通过fork创建出来的子进程

6.2 为什么子进程可以获取环境变量?

核心特性:环境变量具有全局属性,子进程默认继承父进程全部环境变量

结合前文fork知识点:

  • 使用 fork() 创建子进程时,父子进程代码共享,数据采用写时拷贝

  • 父进程bash内部维护一张环境变量表,在创建子进程瞬间,会把这张环境变量表拷贝一份给子进程;

  • 所以我们的C程序(子进程)天然自带一份环境变量表,这就是能通过 env、environ、getenv 获取数据的根本原因。

6.3 底层传递流程(极简流程)

  1. 登录Linux,系统启动bash进程,加载系统环境变量;

  2. 用户在终端输入 ./code,bash调用fork创建子进程(我们的程序);

  3. 创建子进程时,bash将自身环境变量表拷贝给子进程;

  4. 子进程程序运行,通过三种方式读取自身内存中保存的环境变量表。

6.4 关键补充:本地变量为什么不能继承?

  • 普通本地变量(如 MYENV=123 不加export):仅属于当前bash内部,不会拷贝给子进程,程序读取不到,其他bash也无法访问;

  • 环境变量(加export修饰):标记为全局变量,fork创建子进程时强制拷贝,所有子进程均可继承。

一句话总结:环境变量由bash父进程提供,依靠fork创建进程时的继承机制传递给子进程,这就是C语言程序能读取环境变量的本质原因。

6.5 环境变量与本地变量的区别

在学习本地变量与环境变量区别之前,必须先搞懂两个概念:什么是bash内部?什么叫仅在当前bash终端生效?只有弄懂作用域,才能彻底分清两种变量。

0、前置科普:通俗易懂理解bash终端
  • 什么是bash?我们打开的Linux终端,每一个窗口都是一个独立的bash进程,系统会给每一个bash分配唯一PID。

  • 什么叫bash内部?每一个bash进程都有自己独立的内存空间,在该终端定义的变量,存放于当前bash进程内存内部

  • 什么叫仅在当前bash终端?变量只能在定义它的这一个终端内使用,新开一个终端、切换窗口,变量直接消失看不到。

0.1 验证
  1. 打开终端A,定义本地变量:MYNAME=zhangsan

  2. 在终端A输入 echo $MYNAME,可以正常打印变量;

  3. 新建终端B,同样输入 echo $MYNAME无任何输出

  4. 原因:本地变量只存在终端A的bash内存内部,终端B是另一个独立bash,完全看不到。

0.2 通俗人话比喻
  • 每一个bash终端 = 一间独立房间

  • 本地变量 = 房间私有物品,只在这间房能用,别的房间看不见;

  • 环境变量(export) = 公共物品,不仅自己房间能用,自己生的孩子(子进程)也能使用。

在Linux Shell中,变量分为本地变量(临时变量)环境变量(全局变量)。

1、定义概念
  • 本地变量:仅定义在当前bash终端的变量,不会被其他进程识别,不具备继承性。

  • 环境变量:被export修饰、挂载到进程环境表中的变量,具有全局属性,可以被子进程继承

2、创建方式区别

# 1.定义本地变量(无export) MYENV="123"  不进入环境变量表

# 2.定义环境变量(带export) export MYENV="321" 进入环境变量表

3、核心区别汇总表

对比维度

本地变量

环境变量

创建语法

变量名=值

export 变量名=值

作用范围

仅当前bash终端

当前bash + 所有子进程

能否被子进程继承

不能

可以

查看命令

可以用set、echo $查看

env、echo $、set 都能查看

生命周期

关闭终端立即销毁

关闭终端立即销毁(内存级)

是否进入环境变量表

不进入

进入,可被C程序getenv读取

4、实验现象
  1. 只写 MYENV=123:本地变量,C语言程序读取不到

  2. 加上 export MYENV=321:升级为环境变量,子进程程序可以读取

  3. 无论哪种写法,重启终端全部消失,都是临时变量。

5、一句话通俗总结

本地变量只给自己(当前bash)用,环境变量全家(子进程)都能用;export就是把私有变量改成公有变量的指令。

6、bash内部维护两张表

每一个bash进程内存内部,天然维护两张独立的变量表,这是变量区分的底层本质:

  • 第一张:环境变量表:存放被export修饰的变量,支持子进程继承,使用 env、echo 指令可以查看。

  • 第二张:本地变量表(Shell私有变量表):存放无export修饰的普通变量,仅当前bash使用,不支持继承,env无法查看。

指令区分口诀: 1、env:只打印第一张表(环境变量); 2、set:同时打印两张表(本地变量+环境变量)。

7、拓展区分:进程层面的两张表

站在我们编写的程序(子进程)角度,进程内存中也存在两张表,不要和bash两张表混淆:

  • argv[] 命令行参数表:存放执行程序时传入的参数;

  • env[] 环境变量表:从bash父进程继承过来的环境变量。

三、拓展注意事项

若想要永久修改环境变量(重启终端不失效),需要修改系统配置文件 ~/.bashrc/etc/profile,在文件末尾写入export修改指令,执行source 配置文件 生效。但不建议随意修改系统级配置文件,优先使用临时修改方式。

3.1 补充:什么是配置文件?

1、什么是bash配置文件?

配置文件本质:Linux给bash终端准备的开机自动执行的记事本。

  • 每当你打开一个新终端,bash进程启动;

  • bash启动第一件事:自动读取专属配置文件;

  • 文件里面写满了指令、自定义环境变量、PATH路径;

  • 读到什么,bash就初始化什么。

2、为什么修改配置文件可以永久生效?

  • 终端直接export:修改写在内存里,关闭终端,内存释放,全部消失(临时);

  • 修改配置文件:修改写在硬盘文件里,永久保存;每次新开终端,bash自动重读文件,自动加载你的PATH、自定义变量(永久)。

3、两个最常用配置文件区别

配置文件

路径

作用范围

适用人群

用户级配置文件

~/.bashrc

当前普通用户生效

日常开发、个人配置(推荐)

系统级配置文件

/etc/profile

所有用户全部生效

管理员root、系统全局配置

4、source命令是什么?

修改配置文件后,不会立刻生效,因为当前bash不会自动重读文件。

source 文件名:强制让当前终端立刻重新读取配置文件,不用重启终端。

示例:source ~/.bashrc

5、极简总结

  • 配置文件 = bash开机自启动脚本;

  • 写在终端:内存临时生效;

  • 写在配置文件:硬盘永久保存,重启终端不丢失;

  • source:手动刷新配置,不用重启终端。

四、全篇总结

4.1 命令行参数总结

  • 命令行参数是程序运行时,在终端传入的自定义参数,bash以空格拆分参数;

  • main函数参数:argc为参数个数、argv为参数字符串数组,argv[0]永远保存程序名;

  • 作用:无需修改代码,在外部向程序传递数据,Linux系统指令均依赖命令行参数实现功能。

4.2 环境变量核心总结

  • 自定义程序需要加 ./ 执行,是因为当前目录不在PATH默认搜索路径中;系统命令无需加路径,存放在PATH系统目录;

  • PATH错误写法:直接赋值,覆盖系统路径导致命令失效;正确写法:export PATH=$PATH:路径,追加路径;

  • 终端修改PATH属于内存级临时修改,关闭终端自动还原。

4.3 本地变量 & 环境变量总结

  • 每一个Linux终端都是独立bash进程,变量默认存放在当前bash内存中;

  • 本地变量:无export修饰,仅当前bash可用,不能被子进程继承,只能set查看;

  • 环境变量:export修饰,存入环境变量表,可被子进程继承,env、echo、set均可查看;

  • 本质区别:本地变量私有,环境变量共享。

4.4 C语言三种获取环境变量方式

  • main函数env参数:适合遍历所有环境变量,无需额外声明;

  • environ全局变量:底层使用,需要手动extern声明;

  • getenv函数:开发首选,精准查询单个环境变量,代码简洁;

  • 共性:所有环境变量全部由父进程bash继承而来,依靠fork拷贝传递。

4.5 配置文件总结

  • 配置文件是bash开机自启动脚本,新开终端自动读取;

  • 终端修改变量:保存在内存,临时生效;修改配置文件:写入硬盘,永久生效;

  • 用户级 ~/.bashrc 仅个人生效,系统级 /etc/profile 所有用户生效;

  • source命令:手动刷新配置文件,无需重启终端即可生效。

4.6 底层本质一句话汇总

bash作为父进程,自身维护环境变量表,通过fork创建子进程时拷贝环境变量;我们编写的程序本质是子进程,因此可以读取环境变量;而export指令,就是将私有本地变量升级为可继承的公有环境变量。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐