【Linux进程(五)】Linux / Windows命令行参数与环境变量深度解析 | 附代码实验与配置技巧
🎬 个人主页:艾莉丝努力练剑
❄专栏传送门:《C语言》《数据结构与算法》《C/C++干货分享&学习过程记录》
《Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享》
⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平
🎬 艾莉丝的简介:
文章目录
- 本文预告
- 4 ~> 环境变量和命令行参数
- 4.1 命令行参数
- 4.2 环境变量
- 4.2.1 概念
- 4.2.2 常见的环境变量
- 4.2.3 查看环境变量的方法
- 4.2.4 和环境变量相关的指令
- 4.2.5 环境变量的组织方式
- 4.2.6 通过代码如何获取环境变量
- 4.2.7 通过系统调用获取或设置环境变量
- 4.2.8 环境变量通常是具有全局属性的
- 4.2.9 做一做:实验
- 4.2.10 环境变量的实际场景:以vs为例。
- 4.2.11 引入Linux环境变量,3~4个,环境变量命令,扩展Linux常见环境变量
- 4.2.12 获取、设置环境变量
- 4.2.13 理解环境变量的产生,修改文件配置实验
- 4.3 查看并详解系统中所有的环境变量
- 4.4 内建命令
- 本文文章代码演示
- 结尾
本文预告
本文主要是围绕【命令行参数和环境变量】来展开的,重点在于以下四点——

4 ~> 环境变量和命令行参数
环境变量和命令行参数,和进程并不强相关,但是任何OS都要讨论这个问题。
4.1 命令行参数
4.1.1 命令行参数的原理
了解了命令行参数之后,对于理解完整的程序有很大帮助。
main函数一般不用带参数——
解析命令行参数,通常是bash进程来做的——程序替换。
4.1.2 命令行参数可以实现选项功能——以关机程序(shutdown)为例
实现选项功能的原理——命令行参数。
选项——C语言的时候我们写过一个关机程序——系统调用的方式关闭计算机。
用goto语句实现——
#include<stdio.h>#include<stdlib.h>#include<string.h>intmain(){char input[20]={0};system("shutdown - s - t 60"); again:printf("请注意,你的电脑将在一分钟之内关机,如果输入:博主加油,就取消关机\n");scanf("%s", input);if(strcmp(input,"博主加油")==0){system("shutdown - a");printf("关机被取消\n");}else{goto again;}return0;}一般写法——
#define_CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<stdlib.h>intmain(){char input[20]={0};system("shutdown -s -t 60");while(1){printf("你的电脑将在一分钟后关机,输入:博主是帅哥,可以取消关机\n");scanf("%s", input);//数组名不用取地址,数组名本身就是地址;if(strcmp(input,"博主是帅哥")==0){system("shutdown -a");printf("关机程序已关闭\n");break;}}return0;}shutdown带选项——
\s:关闭计算机。\txxx(秒数,0 ~ 10年):设定多久之后关机,默认是30秒。
4.1.3 补充:命令行参数名可以自定义
命令行参数的名字可以自定义的(形参),都是可以改的,argc这种都是约定俗成的,可以改,但是既然已经有约定俗成的名字了,用着就好了,当然虽然如此,还是给了程序员更改的自由。
像这些参数都是可以自定义的,因为是形参。
4.2 环境变量
4.2.1 概念
(1)环境变量(environmentvariables)一般是指在操作系统中用来指定操作系统运行环境的一些参数。(2)如:我们在编写C/C++代码时——具体是在链接的时候——从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。(3)环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性。
4.2.2 常见的环境变量
4.2.3 查看环境变量的方法
echo$NAMENAME:你的环境变量名称。
4.2.3.1 测试PATH
- 1、创建
hello.c文件
#include<stdio.h>intmain(){printf("hello world!\n");return0;}- 2、对比
./hello执行和之间hello执行。 - 3、为什么有些指令可以直接执行,不需要带路径,而我们的二进制程序需要带路径才能执行?
- 4、将我们的程序所在路径加入环境变量PATH当中,
export PATH=$PATH:hello程序所在路径。 - 5、对比测试。
- 6、还有什么方法可以不用带路径,直接就可以运行呢?
4.2.3.2 测试HOME
1、用root和普通用户,分别执行echo $HOME,对比差异。
2、执行cd~;pwd,对应~和HOME的关系。
4.2.4 和环境变量相关的指令
echo:显示某个环境变量值。export:设置一个新的环境变量。env:显示所有环境变量。unset:清除环境变量。set:显示本地定义的shell变量和环境变量。
4.2.5 环境变量的组织方式
每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以‘\0’结尾的环境字符串。

4.2.6 通过代码如何获取环境变量
4.2.6.1 命令行第三个参数
#include<stdio.h>intmain(int argc,char*argv[],char*env[]){int i =0;for(; env[i]; i++){printf("%s\n", env[i]);}return0;}4.2.6.2 通过第三方变量environ获取
#include<stdio.h>intmain(int argc,char*argv[]){externchar**environ;int i =0;for(; environ[i]; i++){printf("%s\n", environ[i]);}return0;}libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时要用extern声明。
4.2.7 通过系统调用获取或设置环境变量
putenv,我们后面介绍。getenv,我们本次介绍。
#include<stdio.h>#include<stdlib.h>intmain(){printf("%s\n",getenv("PATH"));return0;}常用getenv和putenv函数来访问特定的环境变量。
4.2.8 环境变量通常是具有全局属性的
环境变量通常具有全局属性,可以被子进程继承下去。直接查看,发现没有结果,说明该环境变量根本不存在——
#include<stdio.h>#include<stdlib.h>intmain(){char*env =getenv("MYENV");if(env){printf("%s\n", env);}return0;}导出环境变量
exportMYENV="hello world"- 再次运行程序,发现结果有了——说明:
环境变量是可以被子进程继承下去的!我们再思考为什么?
4.2.9 做一做:实验
如果只进行MYENV=“helloworld”,不调用export导出,在用我们的程序查看,会有什么结果?为什么?
- 普通变量。
- 如果时间允许:做一下
~/.bash_profile&&~/.bashrc修改文件级环境变量
4.2.10 环境变量的实际场景:以vs为例。
4.2.10.1 变量:变量名 + 变量的内容
变量名 + 变量的内容——和系统相关。
4.2.10.2 在Windows操作系统中将vs添加到PATH


4.2.11 引入Linux环境变量,3~4个,环境变量命令,扩展Linux常见环境变量
4.2.11.1 PATH
echo $PATH:获取环境变量的内容。
像下面这样是查不到的(后面带的PATH会被当成字符串)——
4.2.11.2 要让myproc执行时候能够不用带任何路径,有两种做法

4.2.11.2.1 做法一:将可执行程序拷贝到系统所指明的路径底下

- 这种做法早在我们为了打消对指令恐惧的时候就已经实践过了——指令本质就是一个二进制可执行程序。
要想改回去——像这样就删除了,再执行myproc就会报错了——
4.2.11.2.2 做法二:把当前路径添加到环境变量里面
最简单粗暴的办法——就是直接把当前路径贴到PATH=后面(会出现问题:大部分的命令跑不起来了,环境变量不是变量吗?改一个变量不就是变量名等于内容吗?)——
我们把当前路径添加到环境变量是要在原有路径之上新增这一段路径,而不是覆盖!
这样一改,系统中绝大部分命令都跑不起来了,只有诸如pwd、echo这样的命令还能跑起来。
说明了一个问题:(这里一覆盖,原来PATH里面的内容就被清掉了)Linux系统能够使用那些命令,是因为在环境变量PATH里面记录了应该去哪里搜索那些命令的搜索路径。
那正确的做法是什么?如下图所示——
4.2.11.3 HOME
echo $HOME:查看家目录。
4.2.11.4 PWD
echo $PwD:查看用户当前所处的路径。
PWD:记录用户当前所处的路径。
4.2.11.5 明明都是用c语言写的,凭什么这些指令使用时可以不带路径,而我们写的myproc要带路径?
4.2.11.6 像pwd、ls、make、top…这些程序可以执行是因为系统会去这些路径下面去找,是找得到的!
4.2.11.7 结论
结论:命令行中,修改环境变量,是内存级修改,退出再重启Xshell就会恢复(根据系统特定的配置文件重新生成)。
4.2.11.8 which命令
[Alice@VM-4-17-centos 12_14]$ which myproc which:搜索环境变量PATH(存在,结束查找)——路径名 + 文件名。
4.2.11.9 环境变量思维导图一
uu们,这里把艾莉丝的上下两张图结合起来看一下就好啦——
4.2.12 获取、设置环境变量
- 指定的可执行程序,只能被我执行!!!
- 代码一
#include<stdio.h>#include<unistd.h>#include<stdlib.h>#include<string.h>intmain(int argc,char*argv[],char*env[]){(void)argc;int i =0;for(;argv[i];i++){printf("argv[%d]: %s\n",i,argv[i]);}printf("----------------------------------\n");for(i =0;env[i];i++){printf("env[%d]: %s\n",i,env[i]);}return0;}- 代码二
#include<stdio.h>#include<unistd.h>#include<stdlib.h>#include<string.h>intmain(){externchar**environ;int i =0;for(;environ[i];i++){printf("environ[%d]: %s\n",i,environ[i]);}return0;}
- 代码三

#include<stdio.h>#include<stdlib.h>#include<string.h>#include<unistd.h>intmain(){printf("PATH: %s\n",getenv("PATH"));printf("HOME: %s\n",getenv("HOME"));printf("PWD: %s\n",getenv("PWD"));printf("HOSTNAME: %s\n",getenv("HOSTNAME"));printf("OK: %s\n",getenv("OK"));return0;}
4.2.13 理解环境变量的产生,修改文件配置实验
4.2.13.1 env:查看环境变量
4.2.13.2 结论
结论:任何进程启动都会存在两张表——1、命令行参数表2、环境变量表
4.2.13.3 环境变量具有全局属性——本质:环境变量被子进程继承了!
这一个一个环境变量值从哪里来的?从系统的配置文件。
环境变量是内存级的?环境变量表是内存级的。

4.2.13.4 环境变量相关命令
前面已经介绍过了,这里不多提——
4.2.13.5 bash也是一门语言(脚本语言)

4.2.13.6 export:把本地变量变成环境变量

4.2.13.7 本地变量:只在bash内部有效

这里OK是被当成字符串处理了。
4.2.13.8 修改文件配置实验的思维导图

4.2.13.8 配置文件:bashrc和bash_profile
4.2.13.8.1 环境变量是从系统的特定的配置文件中来的
环境变量是从系统的特定配置文件中来的。
每一次登录,OS都会给我们提供一个命令行参数(bash进程)服务!
4.2.13.8.2 .bashrc
~/.bashrc:
掩码umask、bash都在开机启动时配置好了——
设置PATH,以及根据uid设置掩码umask——

我们可以更改环境变量,使得重新登录进入XShell时打印下面的话——
4.2.13.8.3 .bash_profile
~/.bash_profile:

4.2.13.8.4 Windows当中的配置文件
如下图,这些就是Windows当中的配置文件——

改环境变量的操作是类似于Linux中改配置文件的操作。4.2.13.9 getenv
getenv:根据名字,获得一个环境变量的内容。
[Alice@VM-4-17-centos 12_14]$ man getenv 
#include<stdio.h>#include<stdlib.h>#include<string.h>#include<unistd.h>intmain(){printf("PATH: %s\n",getenv("PATH"));printf("HOME: %s\n",getenv("HOME"));printf("PWD: %s\n",getenv("PWD"));printf("HOSTNAME: %s\n",getenv("HOSTNAME"));printf("OK: %s\n",getenv("OK"));return0;}4.3 查看并详解系统中所有的环境变量
[Alice@VM-4-17-centos 12_14]$ envXDG_SESSION_ID=172775HOSTNAME=VM-4-17-centos TERM=xterm SHELL=/bin/bash HISTSIZE=3000SSH_CLIENT=113.57.114.181 211422SSH_TTY=/dev/pts/1 USER=Alice LD_LIBRARY_PATH=:/home/Alice/.VimForCpp/vim/bundle/YCM.so/el7.x86_64 LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36: MAIL=/var/spool/mail/Alice PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/Alice/.local/bin:/home/Alice/bin PWD=/home/Alice/118/linux-git/12_14 LANG=en_US.utf8 SHLVL=1HOME=/home/Alice LOGNAME=Alice SSH_CONNECTION=113.57.114.181 211410.0.4.17 22LESSOPEN=||/usr/bin/lesspipe.sh %s PROMPT_COMMAND=history -a;history -a;printf"\033]0;%s@%s:%s\007""${USER}""${HOSTNAME%%.*}""${PWD/#$HOME/~}"XDG_RUNTIME_DIR=/run/user/1003 HISTTIMEFORMAT=%F %T _=/usr/bin/env OLDPWD=/home/Alice/118/linux-git 
4.3.1 env | set
env:查看环境变量——查系统中所有的环境变量。
[Alice@VM-4-17-centos ~]$ envset:显示本地定义的shell变量和环境变量。

4.3.2 HOME
HOME:记录当前用户的身份,记录下当前用户默认的家目录是谁(默认把用户所处的路径设置为家目录)。
说白了就是为什么登录时家目录在你指定的路径下——因为环境变量配置好了。
4.3.3 XDG_SESSION_ID
XDG_SESSION_ID:这个我们不管。
4.3.4 HOSTNAME
HOSTNAME:当前机器的主机名。
HOSTNAME=VM-4-17-centos 为什么会知道你的主机名叫什么?
在环境变量里面已经记录下来了。
4.3.5 TERM
TERM:登录终端是谁——“XXX”。
TERM=xterm TERM=xterm只是一种登录形式。
4.3.6 SHELL
SHELL:代表登陆之后所采用的shell是什么。
SHELL=/bin/bash 用到的shell(媒婆)是bash(王婆)。
4.3.7 SSH_CLIENT
SSH_CLIENT:代表当前的客户端是谁(远程登录)。
SSH_CLIENT=113.57.114.181 2114224.3.8 SSH_TTY
SSH_TTY:代表登录时给用户的终端文件是什么。
SSH_TTY=/dev/pts/1 
4.3.9 USER
USER:代表是谁来登录的。
USER=Alice 启动XShell、创建用户时知道了用户是谁、UID是多少。
4.3.10 LD_LIBRARY_PATH
LD_LIBRARY_PATH:这是关于动态库的,我们后面再介绍。
LD_LIBRARY_PATH=:/home/Alice/.VimForCpp/vim/bundle/YCM.so/el7.x86_64 4.3.11 LS_COLORS
LS_COLORS:这么长一大堆都是ls命令执行时的一些配色方案。
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36: 4.3.12 PATH
PATH:命令行参数在搜索可执行程序时带的路径。
PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/Alice/.local/bin:/home/Alice/bin 4.3.13 PWD
PWD:当前用户所处的工作路径。
PWD=/home/Alice/118/linux-git/12_14 4.3.14 LANG
LANG:代表语言和编码格式。
LANG=en_US.utf8 4.3.15 HOME
HOME:代表当前的家目录。
HOME=/home/Alice 4.3.16 LOGNAME
LOGNAME:代表当前真实登录的用户是谁。
LOGNAME=Alice 4.3.17 OLDPWD
OLDPWD:上一次的工作路径。
用cd -可以做到在最近两次路径间来回跳转 / 切换。
OLDPWD=/home/Alice/118/linux-git 4.4 内建命令

像下面这种都是内置命令——
shell语法,.属于内置命令。本文文章代码演示
Makefile
myproc:myproc.c gcc -o $@ $^-std=c99 .PHONY:clean clean: rm -f myproc #myproc:myproc.c#gcc-o $@ $^ #.PHONY:clean #clean:#rm-f myprocmyproc.c
//#include<stdio.h>//#include<unistd.h>//#include<stdlib.h>//#include<string.h>////int main()//{// printf("PATH: %s\n",getenv("PATH"));// printf("HOME: %s\n",getenv("HOME"));// printf("PWD: %s\n",getenv("PWD"));// printf("HOSTNAME: %s\n",getenv("HOSTNAME"));// printf("OK: %s\n",getenv("OK"));//// extern char **environ;// int i = 0;// for(;environ[i];i++)// {// printf("environ[%d]: %s\n",i,environ[i]);// }// // return 0;//}//int main(int argc,char *argv[],char *env[])//{// (void)argc;// int i = 0;// for(;argv[i];i++)// {// printf("argv[%d]: %s\n",i,argv[i]);// }// printf("----------------------------------\n");// for(i = 0;env[i];i++)// {// printf("env[%d]: %s\n",i,env[i]);// }//// return 0;//}//int main()//{// char *who = getenv("USSR");// if(strcmp(who,"whb") == 0)// {// printf("我是一个命令,变成了进程运行\n");// }// else{// printf("权限错误,不认识你: %s\n",who);// }// return 0;//}//int main()//{// printf("我是一个命令,变成了进程运行\n");// return 0;//}//int main(int argc,char *argv[])//{// (void)argc;// if(strcmp(argv[1],"-a") == 0)// {// printf("这是我的程序的功能1\n");// }// else if(strcmp(argv[1],"-b") == 0)// {// printf("这是我的程序的功能2\n");// }// else// {// printf("这是我的程序的默认功能\n");// }// int i = 0;// for(;i < argc;i++)// {// printf("argv[%d]:%s\n",i,argv[i]);// } //// return 0;//}//int main(int argc,char *argv[])//{// int i = 0;// for(;i < argc;i++)// {// printf("argc[%d]: %s\n",i,argv[i]);// }// return 0;//}结尾
uu们,本文的内容到这里就全部结束了,艾莉丝在这里再次感谢您的阅读!
结语:希望对学习Linux相关内容的uu有所帮助,不要忘记给博主“一键四连”哦!
往期回顾:
【Linux进程(四)】深入理解 Linux O(1) 调度器:双队列轮转与进程优先级机制——如何避免进程饥饿,实现公平且高效的进程调度
🗡博主在这里放了一只小狗,大家看完了摸摸小狗放松一下吧!🗡૮₍ ˶ ˊ ᴥ ˋ˶₎ა