C/C++命令行参数和环境变量的使用

发布时间:2026/7/9 12:07:36
C/C++命令行参数和环境变量的使用 C/C命令行参数和环境变量的使用命令行参数Linux环境变量环境变量的存在进程获取环境变量的方法用户程序像指令一样使用程序安装永久添加指令环境变量有关配置文件本地变量export指令和本地变量修改配置文件添加环境变量和环境变量相关的命令环境变量有关的常用命令内建命令命令行参数命令行参数也称为位置参数是用户在启动一个可执行程序、命令或脚本时在命令名后面输入的额外信息。这些信息用于向程序传递数据、选项或配置从而改变程序的行为。在 C 语言中main函数是进程的入口进程启动时命令行参数的各个信息都保存在main函数的前 2 个形参中。同样取决于编译器至少 gcc 系列和 MSVCVisual Studio 2019 是如此其他的编译器不保证。其他的例如嵌入式环境直白点说就是 “裸机” 环境程序入口点可能不是main函数形参处同样为void表示空。还有远古时代的编译器以void main(){}作为程序入口这种也没有存储命令行参数的形参。例如这里打印命令行参数的信息。#includestdio.hintmain(intargc,char*argv[]){for(inti0;iargc;i)printf(%d %s\n,i,argv[i]);printf(\nhello, world.\n);return0;}交互界面[BjarneVM-8-8-centos cTest]$ ./a.exe0./a.exe hello, world.[BjarneVM-8-8-centos cTest]$会发现在 Shell 的命令以字符串的形式可通过argv数组获取。指令都可以通过新增选项来实现不同的功能都是在启动进程时进行添加。所以在启动进程时添加的选项只要用空格作为分隔符进行隔开都可以被进程识别。[BjarneVM-8-8-centos cTest]$ ./a.exe-a--b---c--version# 至少1个空格0./a.exe1-a2--b3---c4--versionhello, world.[BjarneVM-8-8-centos cTest]$这个识别工作是由 Shell 去完成。即通过命令行启动的子进程的命令行参数和后文要提到的环境变量都是父进程bash传递给子进程的。简单理解就是 bash 会传递给main函数两张表一张命令行参数表argv另一张是环境变量表env。在命令中执行指令时至少要传一个程序名称所以argv[0]就是指定的程序名称。通过这个特性可以实现一个程序通过不同的选项来指定这个程序要完成的功能。例如简易的mytouch命令#includestdio.hintmain(intargc,char*argv[]){if(argc2)//命令行参数至少有2个return-1;fclose(fopen(argv[1],w));return0;}交互界面[BjarneVM-8-8-centos cTest]$ gcc a.c-omytouch[BjarneVM-8-8-centos cTest]$lsa.c a.exe makefile mytouch oldMake[BjarneVM-8-8-centos cTest]$ ./mytouch t.txt[BjarneVM-8-8-centos cTest]$lsa.c a.exe makefile mytouch oldMake t.txt[BjarneVM-8-8-centos cTest]$Linux环境变量用户自己写的程序需要指定可执行程序的相对路径才能运行例如带个./指定可执行程序在当前位置。而指令只需要输入指令名就可以运行。所以执行一个程序需要指定程序的位置。而ls、pwd这些指令存在一个默认搜索路径Shell 通过这个搜索路径就能找到指令所在。所以环境变量就是用来记录这个搜索路径的工具。环境变量environment variables一般是指在操作系统中用来指定操作系统运行环境的一些参数。例如程序员编写 C/C 代码的时候在链接的时候从来不知道所链接的动态静态库在哪里但是照样可以链接成功生成可执行程序原因就是有相关环境变量帮助编译器进行查找。环境变量通常具有某些特殊用途还有在系统当中通常具有全局特性即在操作系统的命令行交互界面可查看以及能被所有进程识别。环境变量的存在指令echo $NAME查看环境变量 ”NAME“ 的内容。若不加$echo会将后文识别为普通字符串。常见的环境变量PATH指定命令的搜索路径。HOME指定用户的主工作目录即用户登陆到 Linux 系统中时默认的目录。普通用户则是/home/usernameroot 用户则是/root。SHELL当前 Shell它的值通常是/bin/bash。PWD存储着当前工作目录的绝对路径。指令pwd会从 PWD 中读取工作目录。可以看到一般环境变量都是大写的。在用户登录时会从配置文件中读取环境变量并生成。登录的大致流程如下输入用户名和密码。认证。认证成功创建会话读取配置文件形成环境变量不止一个PATHPWDHOME等。例如根据用户名初始化 HOME root 账户HOME/root普通账户HOME/XXX等cd $HOME。交互界面查看环境变量[BjarneVM-8-8-centos cTest]$echo$PATH/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/Bjarne/.local/bin:/home/Bjarne/bin[BjarneVM-8-8-centos cTest]$echo$PWD/home/Bjarne/work/cTest[BjarneVM-8-8-centos cTest]$cd$HOME[BjarneVM-8-8-centos ~]$echo$PWD/home/Bjarne[BjarneVM-8-8-centos ~]$通过echo指令看到的环境变量的内容是由:作为分隔符的路径字符串组成的字符串。当用户输入指令时例如ls则 Shell 或操作系统会按环境变量的顺序在路径下搜索ls指令找不到则继续搜索下一个路径。还可以通过指令env查看所有环境变量。[BjarneVM-8-8-centos ~]$envXDG_SESSION_ID133145# 省略USERBjarne# 省略PATH/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/Bjarne/.local/bin:/home/Bjarne/binPWD/home/Bjarne# 当前工作目录LANGen_US.utf8# 语言SHLVL1HOME/home/Bjarne# 当前用户的家目录# 省略[BjarneVM-8-8-centos ~]$进程获取环境变量的方法这里主要记录 3 个常用的方法C 语言的库函数getenv。main函数的第 3 个参数char* env[]。外部全局变量char** environ。程序可以通过库函数getenv获取环境变量的值。main函数也支持第 3 个形参用于存储环境变量但不是所有的编译器都支持第 3 个形参也不是因此进程获取环境变量最合适的方法还是getenv这个库函数被写进 C语言的标准中流通的编译器都会遵循 C 语言的标准。#includestdio.h#includestdlib.h// 使用库函数getenv需要展开头文件stdlib.h// Windows下的MSVC也可用intmain(intargc,char*argv[],char*env[]){for(inti0;env[i];i)printf(%s\n,env[i]);printf(\n);printf(%s\n,getenv(PATH));return0;}交互界面[BjarneVM-8-8-centos cTest]$ ./a.exeXDG_SESSION_ID133145HOSTNAMEVM-8-8-centos# 省略大量信息OLDPWD/home/Bjarne# 单独输出PATH的值/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/Bjarne/.local/bin:/home/Bjarne/bin[BjarneVM-8-8-centos cTest]$还可以通过extern关键字导入外部变量environ获取环境变量。libc中Linux自带的标准库定义的全局变量environ指向环境变量表environ没有包含在任何头文件中所以在使用时要用extern声明。注意 Windows 的环境变量指针是_environ所以environ可以在 Linux 使用但在 Windows 需要使用_environ。#includestdio.h#includestdlib.hintmain(intargc,char*argv[]){externchar**environ;// Windows换成_environinti0;for(;environ[i];i){printf(%s\n,environ[i]);}return0;}程序运行效果和命令行参数env没有区别这里就不演示交互界面了。environ变量的环境变量的组织方式每个程序都会收到一张环境变量表和命令行参数表。环境表和命令行参数表都是字符指针数组每个指针元素指向一个以\0结尾的环境字符串最后一个指针元素指向 NULL。至于argv最后一个元素指向 NULL依旧有argc这个冗余的形参存在是因为历史的原因。换个角度想argc可以表示命令行参数的数量减少了直接遍历argv统计数量的情况使得程序可以完成更多功能。知道了如何获取环境变量程序也可以变得更灵活。例如某个程序只允许 root 账户登录则设置条件判断。这也是很多指令为什么会设置选项的原因。intmain(){char*whogetenv(USER);if(strcmp(who,root)!0){//用户非root不允许执行printf(非法用户\n);return0;}//...return0;}用户程序像指令一样使用一般情况下路径并没有将用户的程序添加到环境变量中所以需要指定相对路径来让操作系统找到程序的位置。想让用户程序像指令一样使用可以通过赋值的方式修改环境变量的值。赋值方式PATH/home/Bjarne/work/cTest例如原来的 mytouch 可执行程序[BjarneVM-8-8-centos cTest]$echo$PATH# 查看环境变量的值/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/Bjarne/.local/bin:/home/Bjarne/bin[BjarneVM-8-8-centos cTest]$pwd/home/Bjarne/work/cTest# 查看当前路径并覆盖环境变量[BjarneVM-8-8-centos cTest]$PATH/home/Bjarne/work/cTest[BjarneVM-8-8-centos cTest]$echo$PATH/home/Bjarne/work/cTest# 用户的程序不需要指定相对路径也能使用[BjarneVM-8-8-centos cTest]$ mytouch t.txt[BjarneVM-8-8-centos cTest]$ls# 覆盖PATH的代价是找不到原来的部分指令-bash: ls:commandnot found[BjarneVM-8-8-centos cTest]$\ls -bash: ls:commandnot found# 只能通过相对或绝对路径来找[BjarneVM-8-8-centos cTest]$ /usr/bin/ls# 这里不会显示文件高亮区分文件a.c a.exe makefile mytouch oldMake t.txt# 文件t.txt创建成功[BjarneVM-8-8-centos cTest]$ ./../../../../usr/bin/ls# 相对路径a.c a.exe makefile mytouch oldMake t.txt[BjarneVM-8-8-centos cTest]$PATH/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/Bjarne/.local/bin:/home/Bjarne/bin# 还原环境变量的值[BjarneVM-8-8-centos cTest]$lsa.c a.exe makefile mytouch oldMake t.txt[BjarneVM-8-8-centos cTest]$很多时候我们作为用户并不是想要覆盖 PATH 的值而是将我们的程序也加到环境变量中所以需要使用变量让 Shell 识别原来的值即赋值时用$PATH表示 PATH 原来的值。例如添加新路径到环境变量PATH$PATH:/home/Bjarne/work/cTest交互界面[BjarneVM-8-8-centos cTest]$lsa.c a.exe makefile mytouch oldMake[BjarneVM-8-8-centos cTest]$echo$PATH/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/Bjarne/.local/bin:/home/Bjarne/bin[BjarneVM-8-8-centos cTest]$pwd/home/Bjarne/work/cTest# 将新地址添加到环境变量中[BjarneVM-8-8-centos cTest]$PATH$PATH:/home/Bjarne/work/cTest[BjarneVM-8-8-centos cTest]$echo$PATH/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/Bjarne/.local/bin:/home/Bjarne/bin:/home/Bjarne/work/cTest[BjarneVM-8-8-centos cTest]$ mytouch t.txt[BjarneVM-8-8-centos cTest]$lsa.c a.exe makefile mytouch oldMake t.txt[BjarneVM-8-8-centos cTest]$删除环境变量同理可以通过覆盖环境变量的值来实现。程序安装永久添加指令之前的修改环境变量的方法都是修改内存中的环境变量的信息或者说改的是 bash 进程内部的环境变量信息。所以之前的修改环境变量都是暂时的关闭终端后内存数据被清理再启动时会恢复原来的 PATH。因为操作系统每次启动都会从自带的脚本配置文件中读取预设的数据生成环境变量。[BjarneVM-8-8-centos cTest]$pwd/home/Bjarne/work/cTest# 修改环境变量[BjarneVM-8-8-centos cTest]$PATH$PATH:/home/Bjarne/work/cTest[BjarneVM-8-8-centos cTest]$echo$PATH/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/Bjarne/.local/bin:/home/Bjarne/bin:/home/Bjarne/work/cTest[BjarneVM-8-8-centos cTest]$# 这里关闭xshell[BjarneVM-8-8-centos cTest]$echo$PATH# 再启动时环境变量恢复原样/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/Bjarne/.local/bin:/home/Bjarne/bin[BjarneVM-8-8-centos cTest]$父进程例如 bash把命令行参数和环境变量要传递给子进程前提条件是这个父进程本身有数据。而父进程的数据来源是磁盘上的配置文件。所以更改环境变量仅限于本次登录关闭 Shell 将会重启所有环境变量。想让用户自身的进程和指令一样生效可以将可执行程序移动到环境变量指定的目录下。例如将之前的mytouch移动到/usr/bin目录下。[BjarneVM-8-8-centos cTest]$lsa.c a.exe makefile mytouch oldMake[BjarneVM-8-8-centos cTest]$sudomvmytouch /usr/bin/mytouch# 移动可执行文件mytouch需要root权限[BjarneVM-8-8-centos cTest]$lsa.c a.exe makefile oldMake[BjarneVM-8-8-centos cTest]$ mytouch t.txt[BjarneVM-8-8-centos cTest]$lsa.c a.exe makefile oldMake t.txt[BjarneVM-8-8-centos cTest]$这种将可执行程序移植到PATH或其他环境变量包含的目录下的行为可以理解为最简易的程序安装从 PATH 包含的目录下移出可执行程序同样可以理解为最简易的程序卸载。环境变量有关配置文件但程序安装用的还是原来的环境变量。想要添加环境变量还是需要修改配置文件。这个配置文件可以在家目录中找到。[BjarneVM-8-8-centos cTest]$cd$HOME[BjarneVM-8-8-centos ~]$ls-al|grepbash_profile -rw-r--r--1Bjarne Bjarne193Apr12020.bash_profile[BjarneVM-8-8-centos ~]$.bash_profile内部是脚本语言。脚本语言也是一门计算机语言有自己的判断、循环和函数。用户把要执行的若干条命令写在一个配置文件里然后交给Shell让 Shell 把写好的命令从上往下按顺序执行这个配置文件就叫做Shell脚本。在 Shell 启动登录账号时会自动执行这个文件里的内容从而形成环境变量信息。[BjarneVM-8-8-centos ~]$cat.bash_profile# .bash_profile# Get the aliases and functionsif[-f~/.bashrc];then.~/.bashrcfi# User specific environment and startup programsPATH$PATH:$HOME/.local/bin:$HOME/binexportPATH[BjarneVM-8-8-centos ~]$从这里就可以看到 PATH 环境变量的初始配置了。从.bash_profile文件中可以找到这个配置文件还会先执行另一个.bashrc配置文件。和环境变量有关的文件还有一个.bashrc。[BjarneVM-8-8-centos ~]$ls-al|grepbashrc -rw-r--r--1Bjarne Bjarne354Sep620:53 .bashrc[BjarneVM-8-8-centos ~]$有了配置文件.bashrc和.bash_profile后便可开始添加永久的环境变量了。本地变量export指令和本地变量在bash提供的交互界面中允许用户设置本地变量[BjarneVM-8-8-centos cTest]$MYENVhelloworld[BjarneVM-8-8-centos cTest]$echo$MYENVhelloworld[BjarneVM-8-8-centos cTest]$a3[BjarneVM-8-8-centos cTest]$b5[BjarneVM-8-8-centos cTest]$c53[BjarneVM-8-8-centos cTest]$echo$a3[BjarneVM-8-8-centos cTest]$echo$c53[BjarneVM-8-8-centos cTest]$这些本地变量同样是在内存中申请的并没有保存到磁盘下次重启Shell时还是会消失查询环境变量也查不到这些本地变量。[BjarneVM-8-8-centos cTest]$MYENVhelloworld[BjarneVM-8-8-centos cTest]$echo$MYENVhelloworld[BjarneVM-8-8-centos cTest]$env|grepMYENV[BjarneVM-8-8-centos cTest]$想让它变成环境变量还需要使用export命令。[BjarneVM-8-8-centos cTest]$MYENVhelloworld[BjarneVM-8-8-centos cTest]$echo$MYENVhelloworld[BjarneVM-8-8-centos cTest]$exportMYENV[BjarneVM-8-8-centos cTest]$env|grepMYENVMYENVhelloworld# 可以在环境变量表中找到自定义的环境变量了[BjarneVM-8-8-centos cTest]$使用export命令添加环境变量后也能被后续的子进程给识别。例如这个代码输出环境变量#includestdio.hintmain(intargc,char*argv[]){externchar**environ;inti0;for(;environ[i];i){printf(%s\n,environ[i]);}return0;}交互界面[BjarneVM-8-8-centos cTest]$MYENV$PWD[BjarneVM-8-8-centos cTest]$echo$MYENV/home/Bjarne/work/cTest[BjarneVM-8-8-centos cTest]$env|grepMYENVMYENV/home/Bjarne/work/cTest[BjarneVM-8-8-centos cTest]$lsa.c a.exe makefile mytouch oldMake[BjarneVM-8-8-centos cTest]$ gcc a.c-oa.exe-stdc99[BjarneVM-8-8-centos cTest]$ ./a.exe# 省略PWD/home/Bjarne/work/cTestMYENV/home/Bjarne/work/cTest# 找到了自己定义的环境变量HISTTIMEFORMAT%F %T# 省略[BjarneVM-8-8-centos cTest]$修改配置文件添加环境变量但即使是export也只是将本地变量导入bash进程上下文中重启后导入的本地变量还是会消失。所以这里修改配置文件.bash_profile。[BjarneVM-8-8-centos cTest]$lsa.c a.exe makefile mytouch oldMake[BjarneVM-8-8-centos cTest]$vim~/.bash_profile[BjarneVM-8-8-centos cTest]$cat~/.bash_profile# 省略...exportMYENV/home/Bjarne/work/cTest# 这个就是用户添加的环境变量PATH$PATH:$HOME/.local/bin:$HOME/bin:$MYENV# 将新增的MYENV添加到PATH中exportPATH[BjarneVM-8-8-centos cTest]$此时再将 Shell 重启Shell 会按照修改过的配置文件读取环境变量信息并导入内存。之后在命令行启动的子进程以及子进程再创建的子进程都会继承这个环境变量。例如这里将 cTest 目录添加到 PATH 中再重启后发现自己创造的可执行程序也能像正常指令一样使用。[BjarneVM-8-8-centos cTest]$ls# 这里已经重启过a.c a.exe makefile mytouch oldMake[BjarneVM-8-8-centos cTest]$echo$PATH# 再看PATH环境变量/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/Bjarne/.local/bin:/home/Bjarne/bin:/home/Bjarne/work/cTest[BjarneVM-8-8-centos cTest]$pwd/home/Bjarne/work/cTest[BjarneVM-8-8-centos cTest]$ mytouch t.txt[BjarneVM-8-8-centos cTest]$lsa.c a.exe makefile mytouch oldMake t.txt所以说这些被继承的环境变量叫做系统环境变量这些系统环境变量通常具有全局属性即可被所有进程识别。本地变量和环境变量的区别本地变量在内存中生成只在 bash 进程内部有效不会被子进程继承下去。环境变量通过让所有子进程继承的方式实现自身的全局属性。和环境变量相关的命令环境变量有关的常用命令相关命令有很多这里介绍5个常用的。后续有机会再补充。echo $ENV_NAME显示某个环境变量ENV_NAME的值。export ENV_NAME或export ENV_NAMEThe vars value.设置一个新的环境变量。允许先赋值再设置。env显示所有环境变量。这 3 个在上文已经介绍过。unset清除环境变量。$ unset VARset显示本地定义的shell变量和环境变量。交互界面[BjarneVM-8-8-centos cTest]$exportVAR114514[BjarneVM-8-8-centos cTest]$env|grepVARVAR114514[BjarneVM-8-8-centos cTest]$unsetVAR# 解除环境变量[BjarneVM-8-8-centos cTest]$env|grepVAR# 可以看到无法查到[BjarneVM-8-8-centos cTest]$单独输入set同样可以查询当前 shell 的所有本地变量和环境变量。[BjarneVM-8-8-centos cTest]$alphagomts[BjarneVM-8-8-centos cTest]$exportVAR114514[BjarneVM-8-8-centos cTest]$set|grepalphagoalphagomts# set 输出内容太多用grep筛选[BjarneVM-8-8-centos cTest]$set|grepVARVAR114514[BjarneVM-8-8-centos cTest]$set|grepPATH/PATH/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/Bjarne/.local/bin:/home/Bjarne/binTMPPATH/home/Bjarne/.cache/abrt/lastnotification.4ecREFqF[BjarneVM-8-8-centos cTest]$这些指令还有更深层次的用途但很多时候不一定用得上后期有机会单独出一篇。内建命令部分指令例如echo它并不像grep那样在启动指令时会创建进程因此即使将 PATH 环境变清空后echo也能使用。[BjarneVM-8-8-centos cTest]$PATH[BjarneVM-8-8-centos cTest]$echo$PATH[BjarneVM-8-8-centos cTest]$ls-bash: ls: No suchfileor directory[BjarneVM-8-8-centos cTest]$执行echo就相当于执行bash进程内部的一个函数或 shell 自身的一部分bash 在变成进程前也是 C 语言代码。这样的命令被称为内建命令。其他的通过fork等系统调用生成子进程才能生效的命令叫做外部命令。