Linux篇【5】:Linux 进程概念(五):环境变量

news2025/1/18 6:49:42

目录

环境变量

常见的环境变量

基本概念

查看环境变量内容的方法

测试环境变量PATH

与环境变量相关的命令

Linux操作系统下C/C++程序代码中获取环境变量的方式

环境变量的组织方式

环境变量通常具有全局属性


环境变量

问题:

注意:可执行程序 等价于 命令/指令/工具/软件/程序/二进制文件、

        由上可知,process 是一个可执行程序(64byte),因此,我们也可以称 process 为命令/指令/工具/软件/程序/二进制文件,其次,对于 ls 和 pwd 等等而言,它们可以被称为:命令/指令/工具/软件/程序/二进制文件,也可以被称为可执行程序(64byte)、

        我们自己生成的可执行程序与系统(以 Linux 操作系统为例)指令之间没有区别,他们都是可执行程序,那么为什么系统的可执行程序可以直接运行,不需要添加路径,比如直接运行:ls,ll,whoami 等等,但是我们自己生成的可执行程序要想运行,就必须要加上路径呢?比如:./process,若运行自己生成的可执行程序但不添加路径时,则会出现以下问题:

        原因:在 Linux 操作系统中存在相关的环境变量PATH,其次要知道,要想成功运行一个可执行程序(包括自己生成的可执行程序和系统的可执行程序),就必须要先找到它,当运行的可执行程序(包括自己生成的可执行程序和系统的可执行程序)不添加路径时,Linux 操作系统会默认在环境变量PATH中所存储的路径下去寻找该系统的或者我们自己生成的可执行程序,又因该环境变量PATH中存储了所有的系统可执行程序的所在路径,所以当运行系统的可执行程序但不添加路径时,Linux 操作系统根据环境变量PATH中的路径能够找到该系统的可执行程序,因此当运行系统的可执行程序但不添加路径时,能够成功运行,但是,环境变量PATH中并未保存自己生成的可执行程序的所在路径,因此,当运行自己生成的可执行程序但不添加路径时,Linux 操作系统根据环境变量PATH中的路径不能找到该自己生成的可执行程序,因此当运行自己生成的可执行程序但不添加路径时,不能成功运行,会报错:command not found 、

        当我们运行一个可执行程序(包括系统的可执行程序和自己生成的可执行程序)但不添加路径时,Linux 操作系统默认会根据环境变量PATH中的内容(多个路径),从第一个路径中开始搜索是否其中存在该可执行程序(包括系统的可执行程序和自己生成的可执行程序),若能找到,则可以成功运行,此时搜索结束,若找不到,则在下一个路径中继续搜索,如果所有路径下都不存在该可执行程序(包括系统的可执行程序和自己生成的可执行程序),则会报错:command not found 、

        当运行的可执行程序(包括自己生成的可执行程序和系统的可执行程序)主动添加路径时,则Linux 操作系统会根据该主动添加的路径去寻找该系统的或者我们自己生成的可执行程序,而不会再去环境变量PATH中所存储的路径下去寻找该系统的或者我们自己生成的可执行程序,若我们主动添加的路径下能够找到该自己生成的可执行程序和系统的可执行程序,则就能够成功运行,若找不到,则就会报错,不能成功运行、

拓展:

        若想直接成功运行一个我们自己生成的可执行程序但不带路径,则有如下两种方法:

方法一:

        可以将我们自己生成的可执行程序拷贝一份放到环境变量PATH中的任何一个路径下,其次,由于系统的可执行程序都存储于 /usr/bin 路径下,而环境变量PATH中又包含了该路径,因此,可将我们自己生成的可执行程序拷贝一份放到 /usr/bin 路径下,由此可知,我们能够在环境变量PATH中的 /usr/bin 路径下找到我们自己生成的可执行程序,故,当我们运行该自己生成的可执行程序但不带路径时,也是可以成功运行的,如下所示:

[HJM@hjmlcc ~]$ ls
Makefile  process  process.c
[HJM@hjmlcc ~]$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/HJM/.local/bin:/home/HJM/bin
[HJM@hjmlcc ~]$ ls /usr/bin/process
ls: cannot access /usr/bin/process: No such file or directory
[HJM@hjmlcc ~]$ su -
Password: 
Last login: Wed Jan  4 13:22:37 CST 2023 on pts/1
Last failed login: Fri Jan  6 13:25:21 CST 2023 from 175.23.169.25 on ssh:notty
There were 3623 failed login attempts since the last successful login.
[root@hjmlcc ~]# cp process /usr/bin
cp: cannot stat ‘process’: No such file or directory
[root@hjmlcc ~]# cd /home/HJM
[root@hjmlcc HJM]# ls
Makefile  process  process.c
[root@hjmlcc HJM]# cp process /usr/bin
//注意:此处必须要切换到root用户再进行拷贝,或者可以通过sudo cp process /usr/bin指令来完成
//拷贝、
[root@hjmlcc HJM]# su HJM
[HJM@hjmlcc ~]$ pwd
/home/HJM
[HJM@hjmlcc ~]$ ls
Makefile  process  process.c
[HJM@hjmlcc ~]$ ls /usr/bin/process
/usr/bin/process
[HJM@hjmlcc ~]$ process   //此时直接运行我们自己生成的可执行程序且不带路径,则可以成功运行、
Hello,Lcc!
Hello,Lcc!
^C
[HJM@hjmlcc ~]$ 

        注意:最好不要将自己生成的可执行程序拷贝放到环境变量PATH中的某些路径下,因为可能会造成指令(工具/可执行程序等等)污染,比如:我们如上所示的自己生成的可执行程序放到了环境变量PATH中的路径 /usr/bin 下,如果我们更改了普通文件process.c中的内容,并重新生成了一个名字也为process的自己生成的可执行程序,此时,该名称为process的自己生成的可执行程序与之前放入到环境变量PATH中的路径 /usr/bin 下的名称为process的自己生成的可执行程序并不是同一个自己生成的可执行程序,则有可能会造成混淆,所以最好不要使用这种方法,通过下面的操作将刚刚拷贝到环境变量PATH中的路径 /usr/bin 下的自己生成的可执行程序删除掉:

[HJM@hjmlcc ~]$ ls
Makefile  process  process.c
[HJM@hjmlcc ~]$ process
Hello,Lcc!
Hello,Lcc!
^C
[HJM@hjmlcc ~]$ su    //su -也是可以的、
Password: 
[root@hjmlcc HJM]# ls
Makefile  process  process.c
[root@hjmlcc HJM]# rm /usr/bin/process
rm: remove regular file ‘/usr/bin/process’? y
[root@hjmlcc HJM]# ls /usr/bin/process
ls: cannot access /usr/bin/process: No such file or directory
[root@hjmlcc HJM]# su HJM
[HJM@hjmlcc ~]$ process
bash: process: command not found
[HJM@hjmlcc ~]$ 

也可以通过指令:sudo rm /usr/bin/process 进行删除、


方法二:

        预备知识:在 Linux 命令行以及系统中,也可以定义变量(命令行变量),通常可以定义两种变量(命令行变量),如下所示:

//一:
//1、
[HJM@hjmlcc ~]$ ls
Makefile  process  process.c
[HJM@hjmlcc ~]$ aaaaa=100          //如此定义的变量为本地(普通)变量、
[HJM@hjmlcc ~]$ echo $aaaaa
100
[HJM@hjmlcc ~]$ env | grep aaaaa   //由于这不是环境变量,所以查不到、
[HJM@hjmlcc ~]$ 

//2、
[HJM@hjmlcc ~]$ export bbbbb=123   
//如此定义的变量为环境变量(具有全局属性),在定义本地(普通)变量的同时将其导出,则该本地(普通)变
//量就会变成环境变量,也可以理解为通过这种方式直接定义了环境变量、
[HJM@hjmlcc ~]$ env | grep bbbbb
bbbbb=123
[HJM@hjmlcc ~]$ echo $bbbbb
123
[HJM@hjmlcc ~]$ 

//注意:
//echo $aaaaa可以将普通(本地)变量的内容打印在屏幕上,也可以将环境变量的内容打印在屏幕上,
//如:echo $bbbbb,其次,此处的本地(普通)变量和环境变量均具有临时性,当关闭Xshell且重新登陆用户时
//,之前设置的所有的环境变量和所有的本地(普通)变量均会消失不见、


//二:
//删除变量:
//删除本地(普通)变量或删除环境变量:
//1、删除环境变量、
[HJM@hjmlcc ~]$ pwd
/home/HJM
[HJM@hjmlcc ~]$ export bbbbb=1234
[HJM@hjmlcc ~]$ echo $bbbbb
1234
[HJM@hjmlcc ~]$ env | grep bbbbb
bbbbb=1234
[HJM@hjmlcc ~]$ unset bbbbb
[HJM@hjmlcc ~]$ echo $bbbbb

[HJM@hjmlcc ~]$ env | grep bbbbb
[HJM@hjmlcc ~]$

//2、删除普通(本地)变量、
[HJM@hjmlcc ~]$ pwd
/home/HJM
[HJM@hjmlcc ~]$ aaaaa=1000
[HJM@hjmlcc ~]$ echo $aaaaa
1000
[HJM@hjmlcc ~]$ env | grep aaaaa
[HJM@hjmlcc ~]$ unset aaaaa
[HJM@hjmlcc ~]$ echo $aaaaa

[HJM@hjmlcc ~]$ env | grep aaaaa
[HJM@hjmlcc ~]$ 

 注意:

[HJM@hjmlcc ~]$ ls
Makefile  process  process.c
[HJM@hjmlcc ~]$ echo $PATH   //将环境变量PATH的内容打印在屏幕上、
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/HJM/.local/bin:/home/HJM/bin
[HJM@hjmlcc ~]$ pwd
/home/HJM
[HJM@hjmlcc ~]$ export PATH=/home/HJM  //该操作会把环境变量PATH的内容更改为:/home/HJM
[HJM@hjmlcc ~]$ echo $PATH
/home/HJM
[HJM@hjmlcc ~]$ ls
-bash: ls: command not found
[HJM@hjmlcc ~]$ touch
-bash: touch: command not found
[HJM@hjmlcc ~]$ ll
-bash: ls: command not found
[HJM@hjmlcc ~]$ 

//由于在 Linux 命令行上设置(修改)的环境变量的内容具有临时性,当关闭Xshell,再次重启登录用户时,会
//发现环境变量PATH中的内容又会恢复
//到:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/HJM/.local/bin:/home/HJM/bin
//,这是因为,Linux 操作系统中的环境变量存在于内存中,且不是以文件的形式存在,当再次重启Xshell,登
//录用户时,会重新读取系统中的配置文件,重新生成环境变量,若想要改变原来的环境变量中的内容且保持永
//久有效,即重启Xshell再登录用户时也会保持修改后的内容,则需要更改配置文件,配置文件在系统中,与云
//服务器无关,上述修改环境变量中的内容只是在内存层面进行的修改,不会修改到系统中相关的配置文件,在
//系统中关于每次重启Xshell再登录用户时相关的配置文件一般可以在.bash profile和.bashrc两个普通
//文件中进行设置,了解即可、

        可以将自己生成的可执行程序所在的路径直接添加到环境变量PATH中,这样也可以解决问题,如下所示:

[HJM@hjmlcc ~]$ ls
Makefile  process  process.c
[HJM@hjmlcc ~]$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/HJM/.local/bin:/home/HJM/bin
[HJM@hjmlcc ~]$ process
-bash: process: command not found
[HJM@hjmlcc ~]$ pwd
/home/HJM
[HJM@hjmlcc ~]$ export PATH=$PATH:/home/HJM
//$PATH即拿到了原来的环境变量PATH中的所有内容,再使用:将其与/home/HJM分隔开来,整体再赋值给新
//的环境变量PATH,此时再查看新的环境变量PATH的内容就会出现下面这样的情况,要知道,此处
//的$PATH:/home/HJM等价于/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin
//:/home/HJM/.local/bin:/home/HJM/bin:/home/HJM、
[HJM@hjmlcc ~]$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/HJM/.local/bin:/home/HJM/bin:/home/HJM
[HJM@hjmlcc ~]$ process
Hello,L!
Hello,L!
Hello,L!
^C
[HJM@hjmlcc ~]$ vim process.c
[HJM@hjmlcc ~]$ make
gcc process.c -o process
[HJM@hjmlcc ~]$ ls
Makefile  process  process.c
[HJM@hjmlcc ~]$ process
Hello,Lcc!
Hello,Lcc!
^C
[HJM@hjmlcc ~]$ 

[HJM@hjmlcc ~]$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/HJM/.local/bin:/home/HJM/bin
[HJM@hjmlcc ~]$ which ls
alias ls='ls --color=auto'
	/usr/bin/ls
[HJM@hjmlcc ~]$ which touch
/usr/bin/touch
[HJM@hjmlcc ~]$ which process
/usr/bin/which: no process in (/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/HJM/.local/bin:/home/HJM/bin)
[HJM@hjmlcc ~]$ export PATH=$PATH:/home/HJM
[HJM@hjmlcc ~]$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/HJM/.local/bin:/home/HJM/bin:/home/HJM
[HJM@hjmlcc ~]$ which process
~/process
[HJM@hjmlcc ~]$ 

        注意:which 指令(工具/可执行程序等)是根据环境变量PATH中的所有路径去查找可执行程序(包括自己生成的可执行程序和系统的可执行程序)的、


        在 Linux 操作系统中,存在相关的环境变量PATH,该环境变量PATH中默认保存了所有系统可执行程序的搜索路径,环境变量是在开机或者登录用户时,在 Linux 操作系统中自动形成的一组变量,只要是变量,就一定存在变量名和变量内容,不同的环境变量拥有不同的应用场景,在Linux 操作系统中,存在相关的环境变量,查看环境变量的方式如下所示:

[HJM@hjmlcc ~]$ ls
Makefile  process  process.c
[HJM@hjmlcc ~]$ env    //查看 Linux 操作系统中的环境变量、
XDG_SESSION_ID=571347
HOSTNAME=hjmlcc
TERM=xterm
SHELL=/bin/bash
HISTSIZE=3000
SSH_CLIENT=111.33.240.197 14986 22
SSH_TTY=/dev/pts/0
USER=HJM
LD_LIBRARY_PATH=:/home/HJM/.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/HJM
PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/HJM/.local/bin:/home/HJM/bin
PWD=/home/HJM
LANG=en_US.utf8
SHLVL=1
HOME=/home/HJM
LOGNAME=HJM
SSH_CONNECTION=111.33.240.197 14986 10.0.8.8 22
LESSOPEN=||/usr/bin/lesspipe.sh %s
PROMPT_COMMAND=history -a; printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"
XDG_RUNTIME_DIR=/run/user/1002
HISTTIMEFORMAT=%F %T 
_=/usr/bin/env
[HJM@hjmlcc ~]$ 
[HJM@hjmlcc ~]$ ls
Makefile  process  process.c
[HJM@hjmlcc ~]$ env | grep 'PATH'
LD_LIBRARY_PATH=:/home/HJM/.VimForCpp/vim/bundle/YCM.so/el7.x86_64
PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/HJM/.local/bin:/home/HJM/bin
[HJM@hjmlcc ~]$ env | grep PATH
LD_LIBRARY_PATH=:/home/HJM/.VimForCpp/vim/bundle/YCM.so/el7.x86_64
PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/HJM/.local/bin:/home/HJM/bin
[HJM@hjmlcc ~]$ 
//两种写法得到一样的结果、

打印出环境变量中的内容:

[HJM@hjmlcc ~]$ echo "aaaaa"  //将字符串"aaaaa"打印在屏幕上、
aaaaa
[HJM@hjmlcc ~]$ echo PATH     //此时PATH会被认作是字符串"PATH",并打印在屏幕上、
PATH
[HJM@hjmlcc ~]$ echo $PATH    //将环境变量PATH的内容打印在屏幕上、
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/HJM/.local/bin:/home/HJM/bin
[HJM@hjmlcc ~]$               //:作为分隔符,分隔多个路径、

        注意:以上均是以 Linux 操作系统为例,但还要知道,在 Windows 操作系统中也存在相关的环境变量,此电脑—属性—高级系统设置—环境变量、

拓展:

当运行系统的可执行程序时,我们也可以为其添加路径,如下所示:

[HJM@hjmlcc ~]$ ls
Makefile  process  process.c
[HJM@hjmlcc ~]$ /usr/bin/ls
Makefile  process  process.c
[HJM@hjmlcc ~]$ /usr/bin/pwd
/home/HJM
[HJM@hjmlcc ~]$ 

常见的环境变量

[HJM@hjmlcc ~]$ env  //查看Linux操作系统下所有的环境变量、
XDG_SESSION_ID=582015
HOSTNAME=hjmlcc
TERM=xterm
SHELL=/bin/bash
HISTSIZE=3000
SSH_CLIENT=111.30.235.195 14463 22
...
...
LESSOPEN=||/usr/bin/lesspipe.sh %s
PROMPT_COMMAND=history -a; printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"
XDG_RUNTIME_DIR=/run/user/1002
HISTTIMEFORMAT=%F %T 
_=/usr/bin/env
[HJM@hjmlcc ~]$ 

MANPATH:代表man手册的搜索路径、

HOSTNAME:代表当前使用的云服务器的机器名、

HISTSIZE:在 Linux 命令行中,可以使用上下键调出历史使用过的指令,该环境变量代表最多记录的历史指令条数,使用指令 history 便可查看记录下来的历史指令,还要知道,查询出来的历史指令的编号并不一定是从1开始的,可以使用指令 history | wc -l 来统计所记录下来的历史指令的条数、

PWD:代表当前使用的用户所处的路径(指定当前用户的主工作目录,即用户登陆到Linux操作系统中时,默认的目录)、

HOME:代表当前用户的家目录、

PATH:指定命令(可执行程序等等)的搜索路径、

SHELL: 当前Shell,它的值通常是/bin/bash、

        环境变量都写在配置文件中,当每一次打开Xshell,登录用户时,Linux操作系统都会自动执行相关的配置文件,从而导出环境变量,我们在Linux命令行中修改环境变量的内容时,不会改变配置文件中环境变量里的内容,所以我们每次打开Xshell,登录用户时,Linux操作系统会再次自动执行相关的配置文件,因此,我们在Linux命令行中修改的环境变量的内容具有临时性,当每一次打开Xshell,登录用户时,环境变量中的内容总保持与配置文件中的环境变量里的内容一致、

拓展:

[HJM@hjmlcc ~]$ pwd
/home/HJM
[HJM@hjmlcc ~]$ ls
Makefile  process  process.c
[HJM@hjmlcc ~]$ cd ..
[HJM@hjmlcc home]$ pwd
/home
[HJM@hjmlcc home]$ cd -  // - 代表的是家目录,此处cd -代表的就是进入普通用户HJM的家目录下、 
/home/HJM
[HJM@hjmlcc ~]$ 

基本概念

1、环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数,如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找、
2、环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性、

查看环境变量内容的方法

echo $NAME //NAME:环境变量的名称、

测试环境变量PATH

测试环境变量 PATH 请见上述所示、


拓展:

//1、
[HJM@hjmlcc ~]$ pwd
/home/HJM
[HJM@hjmlcc ~]$ aaa=123  //本地(普通)变量、
[HJM@hjmlcc ~]$ echo $aaa
123
[HJM@hjmlcc ~]$ env | grep aaa
[HJM@hjmlcc ~]$ export aaa=321  //环境变量、
[HJM@hjmlcc ~]$ echo $aaa
321
[HJM@hjmlcc ~]$ env | grep aaa
aaa=321
//在定义本地(普通)变量的同时将其导出,则该本地(普通)变量就会变成环境变量,也可以理解为通过这种
//方式直接定义了环境变量、
[HJM@hjmlcc ~]$ 
//注意:此处的变量aaa由本地(普通)变量变成了环境变量、

//2、
[HJM@hjmlcc ~]$ pwd
/home/HJM
[HJM@hjmlcc ~]$ aaa=123  //本地(普通)变量、
[HJM@hjmlcc ~]$ echo $aaa
123
[HJM@hjmlcc ~]$ env | grep aaa
[HJM@hjmlcc ~]$ export aaa=123  //环境变量、
[HJM@hjmlcc ~]$ echo $aaa
123
[HJM@hjmlcc ~]$ env | grep aaa
aaa=123
//将定义好的本地(普通)变量导出,该本地(普通)变量就会变成环境变量,也可以理解为通过这种方式直接
//定义了环境变量、
//注意:此处的变量aaa由本地(普通)变量变成了环境变量、

//3、
[HJM@hjmlcc ~]$ export zzz=100  //环境变量、
[HJM@hjmlcc ~]$ echo $zzz
100
[HJM@hjmlcc ~]$ env | grep zzz
zzz=100
[HJM@hjmlcc ~]$ zzz=123  //仍是环境变量、
[HJM@hjmlcc ~]$ echo $zzz
123
[HJM@hjmlcc ~]$ env | grep zzz
zzz=123
[HJM@hjmlcc ~]$ 
[HJM@hjmlcc ~]$ qwe=100  //本地(普通)变量、
[HJM@hjmlcc ~]$ echo $qwe
100
[HJM@hjmlcc ~]$ env | grep qwe
[HJM@hjmlcc ~]$ set | grep qwe  //可以查看本地(普通)变量、
qwe=100
[HJM@hjmlcc ~]$ export ewq=200  //环境变量、
[HJM@hjmlcc ~]$ echo $ewq
200
[HJM@hjmlcc ~]$ env | grep ewq
ewq=200
[HJM@hjmlcc ~]$ set | grep ewq  //也可以查看环境变量、
ewq=200
[HJM@hjmlcc ~]$ 

与环境变量相关的命令

  • 1、echo:显示某个环境变量的内容、
  • 2、export:设置一个新的环境变量、
  • 3、env:显示所有的环境变量、
  • 4、unset:清除环境变量或普通(本地)变量、
  • 5、set:显示本地定义的shell变量(普通变量/本地变量)和环境变量、

Linux操作系统下C/C++程序代码中获取环境变量的方式

        Linux操作系统中,在Linux命令行中可以直接使用Linux操作系统拥有的环境变量,而在Linux系统下自己的C/C++程序中没有办法直接使用Linux操作系统拥有的环境变量,需要先获取,再使用,那么如何获取呢?

预备知识:


main函数可以不带参数(形参),也可以带参数,最多可以带三个参数、

int main(int argc, char* argv[], char* envp[])
{
	return 0;
}
//char* argv[]:字符指针数组、
//int argc:该字符指针数组char* argv[]的元素个数为argc+1个、
//char* envp[]:字符指针数组、

我们先谈一下它的前两个参数,先来一段代码作为测试用例:

        如上图所示,argc即为4,我们给main函数传递的形参:int argc 和 char* argv[ ] 称为(Linux)命令行参数,传递的内容本质上就是在Linux命令行中输入的可执行程序的程序名(或是./+可执行程序的程序名)和选项,并且该字符指针数组以空指针NULL结尾,该字符指针数组的元素个数总是要比在Linux命令行中输入的常量字符串的个数多1个、

        main函数所接收到的前两个形参的来源,具体在后期进程控制时再进行阐述、


main函数的前两个形参存在的意义是什么?

通过下面这个例子来回答这个问题:

        实现一个Linux命令行版的计算器,通过在命令行中输入:./process -a 10 20 ,即可自动完成两个 int 类型的整数的相加,通过在命令行中输入:./process -s 10 20 ,即可自动完成两个 int 类型的整数的相减,其他功能具体见如下代码所示:

[HJM@hjmlcc ~]$ ls
Makefile  mycal.c
[HJM@hjmlcc ~]$ cat mycal.c
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(int argc,char* argv[])
{
  //char* argv[]:字符指针数组,该数组有argc+1个元素、
  if(argc!=4)
  {
    printf("Usage:%s [-a|-s|-m|-d] one_data two_data\n",argv[0]);
    return 0;
  }
  int x=atoi(argv[2]);  //将字符指针指向的内容转换为整数、 
  int y=atoi(argv[3]);
  if(strcmp("-a",argv[1])==0)
  {
    //加法
    printf("%d+%d=%d\n",x,y,x+y);
  }
  else if(strcmp("-s",argv[1])==0)
  {
    //减法
    printf("%d-%d=%d\n",x,y,x-y);
  }
  else if(strcmp("-m",argv[1])==0)
  {
    //乘法
    printf("%d*%d=%d\n",x,y,x*y);
  }
  else if(strcmp("-d",argv[1])==0 && y!=0)
  {
    //除法
    printf("%d/%d=%d\n",x,y,x/y);
  }
  else{
    printf("Usage:%s [-a|-s|-m|-d] one_data two_data\n",argv[0]);
  }
  return 0;
}
[HJM@hjmlcc ~]$ make
gcc mycal.c -o mycal
[HJM@hjmlcc ~]$ ./mycal -a 10 20
10+20=30
[HJM@hjmlcc ~]$ ./mycal -s 10 20
10-20=-10
[HJM@hjmlcc ~]$ ./mycal -m 10 20
10*20=200
[HJM@hjmlcc ~]$ ./mycal -d 10 20
10/20=0
[HJM@hjmlcc ~]$ ./mycal 
Usage:./mycal [-a|-s|-m|-d] one_data two_data
[HJM@hjmlcc ~]$ ./mycal -d 10 0
Usage:./mycal [-a|-s|-m|-d] one_data two_data
[HJM@hjmlcc ~]$ 

意义:

        同一份程序代码,通过接收不同的参数(形参),让同一份程序代码有不同的执行逻辑,从而得到不同的执行结果,在Linux命令行中,Linux操作系统会根据不同的选项,让不同的命令(可执行程序等等),可以有不同的表现,这就是指令(命令等等)中各个选项的由来和起作用的方式!!这也就是Linux命令行参数存在的意义,同样也就是main函数中前两个参数存在的意义,在Windows系统下,也是如此、


拓展:

如上图所示,可以完成批量替换,将所有的 process 一次性全部替换成 mycal 、 

实际上,main函数可以带第三个参数(形参),下面我们来具体谈一下:

// C或C++程序代码中获取环境变量的方式:

//方案一:
[HJM@hjmlcc ~]$ ls
Makefile  mycal.c  process.c
[HJM@hjmlcc ~]$ cat process.c
#include<stdio.h>
int main(int argc,char* argv[],char* env[])
{
  //char* env[]:字符指针数组,该字符指针数组的最后一个元素也指向空指针NULL、
  int i=0;
  for(i=0;env[i];i++)
  {
    printf("env[%d]:%s\n",i,env[i]);
  }
  return 0;
}
[HJM@hjmlcc ~]$ gcc process.c
[HJM@hjmlcc ~]$ ls
a.out  Makefile  mycal.c  process.c
[HJM@hjmlcc ~]$ ./a.out
env[0]:XDG_SESSION_ID=586394
env[1]:HOSTNAME=hjmlcc
env[2]:TERM=xterm
env[3]:SHELL=/bin/bash
env[4]:HISTSIZE=3000
env[5]:SSH_CLIENT=111.30.235.195 14443 22
env[6]:SSH_TTY=/dev/pts/1
env[7]:USER=HJM
env[8]:LD_LIBRARY_PATH=:/home/HJM/.VimForCpp/vim/bundle/YCM.so/el7.x86_64
env[9]: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:
env[10]:MAIL=/var/spool/mail/HJM
env[11]:PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/HJM/.local/bin:/home/HJM/bin
env[12]:PWD=/home/HJM
env[13]:LANG=en_US.utf8
env[14]:SHLVL=1
env[15]:HOME=/home/HJM
env[16]:LOGNAME=HJM
env[17]:SSH_CONNECTION=111.30.235.195 14443 10.0.8.8 22
env[18]:LESSOPEN=||/usr/bin/lesspipe.sh %s
env[19]:PROMPT_COMMAND=history -a; printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"
env[20]:XDG_RUNTIME_DIR=/run/user/1002
env[21]:HISTTIMEFORMAT=%F %T 
env[22]:_=./a.out
[HJM@hjmlcc ~]$            //注意: 字符指针数组char* env[]的元素个数与int整型变量argc无关、


//方案二:
//C语言自动定义一个第三方变量(指针变量)environ,属于全局变量、
//1、
[HJM@hjmlcc ~]$ man environ
EXEC(3P)                         POSIX Programmer's Manual                       EXEC(3P)             
PROLOG
       This manual page is part of the POSIX Programmer's Manual.  The Linux implementation of this interface may differ (con‐
       sult the corresponding Linux manual page for details of Linux behavior), or the interface may  not  be  implemented  on
       Linux.

NAME
       environ, execl, execv, execle, execve, execlp, execvp - execute a file

SYNOPSIS
       #include <unistd.h>

       extern char **environ;
       int execl(const char *path, const char *arg0, ... /*, (char *)0 */);
       int execv(const char *path, char *const argv[]);
       int execle(const char *path, const char *arg0, ... /*,
              (char *)0, char *const envp[]*/);
       int execve(const char *path, char *const argv[], char *const envp[]);
       int execlp(const char *file, const char *arg0, ... /*, (char *)0 */);
       int execvp(const char *file, char *const argv[]);

DESCRIPTION
       The  exec  family of functions shall replace the current process image with a new process image. The new image shall be
       constructed from a regular, executable file called the new process image file. There shall be no return from a success‐
       ful exec, because the calling process image is overlaid by the new process image.

       When  a  C-language  program is executed as a result of this call, it shall be entered as a C-language function call as
       follows:

 Manual page environ(3p) line 1 (press h for help or q to quit)

//2、
[HJM@hjmlcc ~]$ ls
Makefile  mycal.c  process.c
[HJM@hjmlcc ~]$ cat process.c
#include<stdio.h>
#include<unistd.h>
int main()
{
  extern char** environ;  //仅仅是声明,不是程序员自己定义的,而是C语言自动定义的、
  int i=0;
  for(i=0;environ[i];i++)
  {
    printf("environ[%d]:%s\n",i,environ[i]);
  }
  return 0;
}
[HJM@hjmlcc ~]$ gcc process.c
[HJM@hjmlcc ~]$ ls
a.out  Makefile  mycal.c  process.c
[HJM@hjmlcc ~]$ ./a.out
environ[0]:XDG_SESSION_ID=586394
environ[1]:HOSTNAME=hjmlcc
environ[2]:TERM=xterm
environ[3]:SHELL=/bin/bash
environ[4]:HISTSIZE=3000
environ[5]:SSH_CLIENT=111.30.235.195 14443 22
environ[6]:SSH_TTY=/dev/pts/1
environ[7]:USER=HJM
environ[8]:LD_LIBRARY_PATH=:/home/HJM/.VimForCpp/vim/bundle/YCM.so/el7.x86_64
environ[9]: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:
environ[10]:MAIL=/var/spool/mail/HJM
environ[11]:PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/HJM/.local/bin:/home/HJM/bin
environ[12]:PWD=/home/HJM
environ[13]:LANG=en_US.utf8
environ[14]:SHLVL=1
environ[15]:HOME=/home/HJM
environ[16]:LOGNAME=HJM
environ[17]:SSH_CONNECTION=111.30.235.195 14443 10.0.8.8 22
environ[18]:LESSOPEN=||/usr/bin/lesspipe.sh %s
environ[19]:PROMPT_COMMAND=history -a; printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"
environ[20]:XDG_RUNTIME_DIR=/run/user/1002
environ[21]:HISTTIMEFORMAT=%F %T 
environ[22]:_=./a.out
[HJM@hjmlcc ~]$           //注意:用此方法所打印出来的环境变量的个数与int整型变量argc无关、


//方案三:
//1、
[HJM@hjmlcc ~]$ man 3 getenv
GETENV(3)                      Linux Programmer's Manual                        GETENV(3)
NAME
       getenv, secure_getenv - get an environment variable

SYNOPSIS
       #include <stdlib.h>

       char *getenv(const char *name);

       char *secure_getenv(const char *name);

   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       secure_getenv(): _GNU_SOURCE

DESCRIPTION
       The getenv() function searches the environment list to find the environment variable name, and returns a pointer to the
       corresponding value string.

       The GNU-specific secure_getenv() function is just like getenv() except that it returns NULL in cases where "secure exe‐
       cution"  is required.  Secure execution is required if one of the following conditions was true when the program run by
       the calling process was loaded:

       *  the process's effective user ID did not match its real user ID or the process's effective group ID did not match its
          real group ID (typically this is the result of executing a set-user-ID or set-group-ID program);

       *  the effective capability bit was set on the executable file; or

       *  the process has a nonempty permitted capability set.
 Manual page getenv(3) line 1 (press h for help or q to quit)
    
//2、
[HJM@hjmlcc ~]$ ls
Makefile  mycal.c  process.c
[HJM@hjmlcc ~]$ cat process.c
#include<stdio.h>            
#include<stdlib.h>
int main()                   //通过putenv在C或C++程序代码中设置环境变量,在后期再进行阐述、
{
  char* val=getenv("PATH");  //返回环境变量PATH中的内容(常量字符串)首元素的地址、
  printf("%s\n",val);
  return 0;                  //常用getenv和putenv函数来访问特定的环境变量、
}
[HJM@hjmlcc ~]$ gcc process.c
[HJM@hjmlcc ~]$ ls
a.out  Makefile  mycal.c  process.c
[HJM@hjmlcc ~]$ ./a.out
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/HJM/.local/bin:/home/HJM/bin
[HJM@hjmlcc ~]$ 

main函数所接收到的第三个形参(char* env[ ])的来源,具体也在后期进程控制时再进行阐述、

总结:一个进程是会被传入环境变量参数的(char* env[ ])、

拓展1:

[HJM@hjmlcc ~]$ ls
Makefile  mycal.c  process.c
[HJM@hjmlcc ~]$ cat process.c
#include<stdio.h>
void fun()
{
  //此处即使没有任何形参,但在该调用函数内部照样可以通过某种方式读取到传递过来的实参:10和20.5,但是过程比较麻烦,了解一下即可、
  printf("Hello,Lcc\n");
}
int main()
{
  fun(10,20.5); 
//当某一个调用函数的声明和定义都没有任何形参时,如上所示:
//此时传实参也能够成功编译的,此处的两个实参也会压栈,也会形成临时变量等等,只不过是在调用函数
//fun内部没有接收而已,在Linux操作系统下编译时不会报错,但是在Windows系统下的Vs编译器下进行编
//译时会报错,这就取决于编译器了,但是如果写成void fun(void)的话,则在Linux下编译时也会报错,
//在Windows下的Vs编译器下进行编译时也会报错,此时在main函数中只能写成fun()才可以,我们之前
//写main函数时一般都不带任何形参,但要知道,本质上是已经给main函数传递了三个参数,只不过是main
//函数并没有接收而已,在Windows下的Vs编译器下编译时,main函数不带任何形参是不会报错的,这一点与
//该例子不同,要注意、
  return 0;
}
[HJM@hjmlcc ~]$ gcc process.c
[HJM@hjmlcc ~]$ ls
a.out  Makefile  mycal.c  process.c
[HJM@hjmlcc ~]$ ./a.out
Hello,Lcc
[HJM@hjmlcc ~]$ 

拓展2:

预备知识:

        首先要明白,环境变量USER的值并不能简单的取决于当前用户,即:环境变量USER的值并不是简单的取决于通过指令whoami得到的值(当前用户),而是,环境变量USER的值代表的是当前登录用户,若当前登录用户发生了改变,那么环境变量USER的值就会随之发生改变,而对于指令 su 而言,只是改变了当前用户(将当前用户改变为root用户),但是并未改变当前登录用户,所以环境变量USER的值不会发生改变,而对于 su - 指令而言,不仅会改变当前用户(将当前用户改变为root用户),还会改变当前登录用户,因此环境变量USER的值也会随之改变,但是要注意,指令su 普通用户,此时不仅会改变当前用户,还会改变当前登录用户,因此环境变量USER的值也会随之改变、

总结:

        通过指令whoami得到的结果只是当前用户,而环境变量USER代表的是当前登录用户

在大部分情况下,当前用户与当前登录用户是一致的,但在部分情况下,指令whoami得到的结果和环境变量USER的值是不一样的(比如普通用户HJM仅仅通过 su 指令,将当前用户切换到了root用户,但是当前登录用户仍是普通用户HJM,因此环境变量USER的值仍是普通用户HJM,而不是root用户),所以我们不能简单的把指令whoami得到的结果(当前用户)直接看做环境变量USER的值、

        环境变量是用来定义操作系统环境的,因此如果操作系统环境没有随用户身份(当前用户)切换的话,很多命令都无法正确执行,su 指令只是切换了当前用户(将当前用户改变为root用户),但是Shell环境并未发生改变,而指令 su - 不仅切换了当前用户(将当前用户改变为root用户),也切换了Shell环境,只用 su 指令不会读取目标用户的环境配置文件,但 su - 指令则会读取,所以我们之后再切换当前用户时,最好都带上 - ,避免出现不必要的错误,su 和 su - 指令在Linux和AIX操作系统下存在一定的区别,在AIX操作系统中一定要加上 - 、

具体请见博客:

su 和su -的区别_水墨胭脂的博客-CSDN博客_su和su -参考文章:(总结)Linux下su与su -命令的本质区别   我一直是习惯使用su username来切换用户的,而且并不知道su和su -有什么区别,一直以为是没啥区别的,但是在一个测试中,在测试的同事的指导下,他说你su - ××× 之后×××,那一刻突然福至心灵觉得可能二者是有区别的,然后执行了su - 用户 之后,果然得到了su 用户的时候得不到的结果。。。。。然后还发现,以前执行dbhttps://blog.csdn.net/nayanminxing/article/details/76424115?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522167335462916800182133259%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=167335462916800182133259&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-2-76424115-null-null.142%5Ev70%5Eone_line,201%5Ev4%5Eadd_ask&utm_term=su%E5%92%8Csu%20-&spm=1018.2226.3001.4187(总结)Linux下su与su -命令的本质区别http://www.ha97.com/4001.html为什么要获取环境变量(在Linux操作系统下的C/C++程序中为什么要获取环境变量)? 

        若在Linux操作系统下写一个只能当前登录用户(以普通用户HJM为例,即环境变量USER的值为普通用户HJM)运行的C/C++程序代码,此时就需要在Linux操作系统下的C/C++程序中获取环境变量,如下所示:

[HJM@hjmlcc ~]$ ls
Makefile  mycal.c  process.c
[HJM@hjmlcc ~]$ cat process.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
  char* id=getenv("USER");
  if(strcasecmp(id,"HJM")!=0)  //比较时忽略大小写、
  { 
    printf("权限拒绝!\n");
  }
  else{
    printf("成功执行!\n");
  }
  return 0;
}
[HJM@hjmlcc ~]$ gcc process.c
[HJM@hjmlcc ~]$ ls
a.out  Makefile  mycal.c  process.c
[HJM@hjmlcc ~]$ whoami
HJM
[HJM@hjmlcc ~]$ echo $USER
HJM
[HJM@hjmlcc ~]$ ./a.out
成功执行!
[HJM@hjmlcc ~]$ su -
Password: 
Last login: Wed Jan 11 11:32:38 CST 2023 on pts/1
[root@hjmlcc ~]# pwd
/root
[root@hjmlcc ~]# cd /home/HJM
[root@hjmlcc HJM]# ls
a.out  Makefile  mycal.c  process.c
[root@hjmlcc HJM]# whoami
root
[root@hjmlcc HJM]# echo $USER
root
[root@hjmlcc HJM]# ./a.out
权限拒绝!
[root@hjmlcc HJM]# su - HJM
Last login: Wed Jan 11 11:34:01 CST 2023 on pts/1
[HJM@hjmlcc ~]$ su
Password: 
[root@hjmlcc HJM]# pwd
/home/HJM
[root@hjmlcc HJM]# whoami
root
[root@hjmlcc HJM]# echo $USER
HJM
[root@hjmlcc HJM]# ls
a.out  Makefile  mycal.c  process.c
[root@hjmlcc HJM]# ./a.out
成功执行!
[root@hjmlcc HJM]# su -
Last login: Wed Jan 11 11:35:15 CST 2023 on pts/1
[root@hjmlcc ~]# su - LCC
Last login: Wed Jan 11 10:52:43 CST 2023 on pts/1
[LCC@hjmlcc ~]$ pwd
/home/LCC
[LCC@hjmlcc ~]$ whoami
LCC
[LCC@hjmlcc ~]$ echo $USER
LCC
[LCC@hjmlcc ~]$ pwd
/home/LCC
[LCC@hjmlcc ~]$ cd /home/HJM
[LCC@hjmlcc HJM]$ ls
a.out  Makefile  mycal.c  process.c
[LCC@hjmlcc HJM]$ ./a.out
权限拒绝!
[LCC@hjmlcc HJM]$ su -
Password: 
Last login: Wed Jan 11 11:58:26 CST 2023 on pts/1
[root@hjmlcc ~]# whoami
root
[root@hjmlcc ~]# echo $USER
root
[root@hjmlcc ~]# su LCC
[LCC@hjmlcc root]$ whoami
LCC
[LCC@hjmlcc root]$ echo $USER
LCC
[LCC@hjmlcc root]$ cd /home/HJM
[LCC@hjmlcc HJM]$ ls
a.out  Makefile  mycal.c  process.c
[LCC@hjmlcc HJM]$ ./a.out
权限拒绝!
[LCC@hjmlcc HJM]$ 

//综上,环境变量一定在某些地方有特殊用途,上面粗略的展示了其中一个方面、 
//由上述例子可推断,我们之前学习 权限 时,底层实现逻辑与此处该例子类似、

环境变量的组织方式

        每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以字符 '\0' 结尾的环境常量字符串、


环境变量通常具有全局属性

        本地(普通)变量只在本Shell内有效,而环境变量则是全局有效,我们从Linux系统的角度来理解一下:

[HJM@hjmlcc ~]$ ls
Makefile  mycal.c  process.c
[HJM@hjmlcc ~]$ cat process.c
#include<stdio.h>
#include<unistd.h>
int main()
{
  while(1)
  {
    printf("Hello,Lcc,PID:%d,PPID:%d\n",getpid(),getppid());
    sleep(2);
  }
  return 0;
}
[HJM@hjmlcc ~]$ gcc process.c
[HJM@hjmlcc ~]$ ls
a.out  Makefile  mycal.c  process.c
[HJM@hjmlcc ~]$ ./a.out
Hello,Lcc,PID:30455,PPID:26215  //PID:30455,PPID:26215
Hello,Lcc,PID:30455,PPID:26215
^C
[HJM@hjmlcc ~]$ ./a.out
Hello,Lcc,PID:30472,PPID:26215  //PID:30472,PPID:26215
Hello,Lcc,PID:30472,PPID:26215
^C
[HJM@hjmlcc ~]$ ./a.out
Hello,Lcc,PID:30480,PPID:26215  //PID:30480,PPID:26215
Hello,Lcc,PID:30480,PPID:26215
^C
[HJM@hjmlcc ~]$ 

//1、
//当运行一个可执行程序时则会得到一个进程,Linux操作系统会为其分配PID,结束(退出)该进程,再次运
//行该可执行程序时又会得到一个新的进程,这两个进程并不是同一个进程,Linux操作系统则会为新的进
//程重新分配PID,所以会得到两个不同的PID,但是这两个进程的父进程是同一个进程(bash进程),所以
//PPID的值是不会发生改变的,其中,当我们打开Xshell并登录用户时,此时bash进程就会被启动,直
//到Xshell被关闭退出时,bash进程才会结束(退出),在此期间,bash进程是一直时实运行的,bash进程就
//是当我们打开Xshell并登录用户时,Linux操作系统给我们创建的一个命令行解释器、

//2、
//若在另外一个SSH渠道中通过指令kill -9 26215来杀掉原来的SSH渠道中的bash进程,则此时在原来的
//SSH渠道中再输入的任何内容都将不会再有任何反应,相当于该SSH渠道下的Linux命令行就挂掉了,这是
//因为,我们在Linux命令行中正常使用指令时(指令又是可执行程序,使用指令就相当于是运行可执行程序
//因此会得到一个进程),这些指令本质上是需要首先被其对应的bash进程(父进程)所获取的,当其对应的
//bash进程(父进程)被杀掉后,我们再使用这些指令时,其对应的bash进程(父进程)就无法正常的获取这些
//指令,因此,这些指令将不再能够正确地发挥其作用了、

//3、
//bash也是一个进程,bash进程所对应的可执行程序所存在的路径为:/usr/bin,当每一次通过Xshell或者其
//他登录软件进行用户登录时,Linux操作系统就会为当前用户创建一个bash进程,因此当我们再一次打
//开Xshell,登录用户时,Linux操作系统就会为当前用户创建一个新的bash进程,再运行可执行程序
//a.out时,该新的bash进程就是该运行可执行程序a.out所得到的进程的父进程,此时PPID就会发生变化,
//因为此时的bash进程和之前的bash进程并不是同一个进程,所以,PPID的值会发生改变、
[HJM@hjmlcc ~]$ ls /usr/bin/bash
/usr/bin/bash
[HJM@hjmlcc ~]$ 

//4、
//bash进程也是使用C/C++写的,因此我们可以使用bash进程对应的可执行程序对应的代码中的scanf或
//cin来获取当前用户在Linux命令行中输入的内容、

//5、
//若打开Xshell登录用户后,新建多个会话,则Linux操作系统会为多个会话各自创建一个bash进程,这多
//个bash进程并不是同一个进程,所以这多个bash进程的PID的值是不同的、

        在Linux命令行中启动的进程(包括运行自己生成的可执行程序与运行系统的可执行程序所得到的进程)的父进程全部都是bash进程,bash进程的底层逻辑也是通过fork的形式来创建子进程的,至于fork之后,Linux操作系统是如何将自己生成的可执行程序或系统的可执行程序加载进来并被运行从而形成进程的,以及bash进程的子进程又是如何被启动并为子进程传递Linux命令行参数和环境变量参数的问题,在后期的进程控制中再进行具体的阐述、


环境变量通常具有全局属性:

[HJM@hjmlcc ~]$ ls
Makefile  mycal.c  process.c
[HJM@hjmlcc ~]$ cat process.c
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
  while(1)
  {
    printf("Hello,Lcc,PID:%d,PPID:%d,myenv=%s\n",getpid(),getppid(),getenv("LCC"));
    sleep(1);
  }
  return 0;
}
[HJM@hjmlcc ~]$ gcc process.c
[HJM@hjmlcc ~]$ ls
a.out  Makefile  mycal.c  process.c
[HJM@hjmlcc ~]$ ./a.out
Hello,Lcc,PID:29911,PPID:9456,myenv=(null)     //不存在环境变量LCC、
Hello,Lcc,PID:29911,PPID:9456,myenv=(null)
Hello,Lcc,PID:29911,PPID:9456,myenv=(null)
Hello,Lcc,PID:29911,PPID:9456,myenv=(null)
Hello,Lcc,PID:29911,PPID:9456,myenv=(null)
^C
[HJM@hjmlcc ~]$ LCC=100                        //定义在bash进程内部的本地(普通)变量、
[HJM@hjmlcc ~]$ gcc process.c
[HJM@hjmlcc ~]$ ls
a.out  Makefile  mycal.c  process.c
[HJM@hjmlcc ~]$ ./a.out
//此时在Linux命令行中运行可执行程序a.out则会启动一个进程,该进程的父进程是bash进程,而本地(普通
//)变量LCC定义在bash进程的内部,但本地(普通)变量不能被子进程继承下去,所以对于bash进程的子进
//程(此处由运行可执行程序a.out所得的进程)而言,是不能从bash进程内部继承到本地(普通)变量LCC的,
//所以此处对于该子进程而言,仍然不存在环境变量LCC、
Hello,Lcc,PID:30316,PPID:9456,myenv=(null)
Hello,Lcc,PID:30316,PPID:9456,myenv=(null)     //不存在环境变量LCC、
Hello,Lcc,PID:30316,PPID:9456,myenv=(null)
^C
[HJM@hjmlcc ~]$ echo $LCC
100
[HJM@hjmlcc ~]$ env | grep LCC
[HJM@hjmlcc ~]$ set | grep LCC
LCC=100
[HJM@hjmlcc ~]$ export LCC
//将定义好的本地(普通)变量导出,该本地(普通)变量就会变成环境变量,该环境变量也相当于是定义在bash进程内部的、
[HJM@hjmlcc ~]$ echo $LCC
100
[HJM@hjmlcc ~]$ set | grep LCC
LCC=100
[HJM@hjmlcc ~]$ env | grep LCC
LCC=100
[HJM@hjmlcc ~]$ ./a.out
Hello,Lcc,PID:31302,PPID:9456,myenv=100     //存在环境变量LCC、
Hello,Lcc,PID:31302,PPID:9456,myenv=100
Hello,Lcc,PID:31302,PPID:9456,myenv=100
^C
[HJM@hjmlcc ~]$ 
//此时在Linux命令行中运行可执行程序a.out则会启动一个进程,该进程的父进程是bash进程,环境变量
//LCC定义在bash进程的内部,但环境变量能够被子进程继承下去,所以对于bash进程的子进程(此处由运行
//可执行程序a.out所得的进程)而言,是能够从bash进程内部继承到环境变量LCC的,所以此处对于该子进
//程而言,可以使用环境变量LCC,故得出上述结果、

总结:

        当我们打开Xshell,登录用户后,bash进程便被启动了,我们此时所在的页面就是在bash进程内部,因此,在Linux命令行中定义的本地(普通)变量或环境变量都是在bash进程内部定义的,而所谓的环境变量具有全局性,在全局均有效的意思即指:环境变量是能够被子进程继承下去的!!!,若我们在Linux命令行中定义了一个环境变量,即相当于在bash进程的内部定义了一个环境变量,又因环境变量能够被子进程继承,所以,该环境变量会被bash进程的所有子进程均继承,而对于bash进程的子进程而言,也存在与之对应的子进程,并且环境变量能够被子进程继承,所以该环境变量能够被bash进程的子进程的子进程继承,由此可知,若在bash进程内部定义了一个环境变量,则该环境变量会被bash进程的所有子进程继承,所谓继承也即代表着能够使用该环境变量,由于在bash进程的内部定义的该环境变量,所以对于bash进程而言可以使用该环境变量,再由上可知,bash进程的所有的子进程均能使用该定义在bash进程内部的环境变量,总结来说就是,bash进程以及bash进程后面所有的子进程均可使用该定义在bash进程内部的环境变量,这就是所谓的环境变量具有全局性,即在全局均有效、

        在Linux命令行中定义的本地(普通)变量也是在bash进程的内部定义的,但是本地(普通)变量不会被子进程继承下去,也就是说,由于本地(普通)变量是在bash进程内部定义的,所以在bash进程的内部是可以使用该本地(普通)变量的,但又因为本地(普通)变量不会被子进程继承下去,所以在bash进程的所有子进程中(bash进程除外)都不能使用该本地(普通)变量,只能在bash进程内部使用该本地(普通)变量,所谓的本地(普通)变量只在本Shell内有效,即指本地(普通)变量只能在bash进程内部有效,要注意,此处不考虑bash进程与其所有子进程的包含与被包含关系,默认为bash进程与其所有的子进程之间两两互相独立、

残留问题:

        在Linux命令行中输入的所有内容,一定需要先被bash进程读取,在bash进程内部对这些内容进行分析,将本地(普通)变量和环境变量保存在bash进程内部的变量列表中,保存在bash进程内部的进程上下文中、


[HJM@hjmlcc ~]$ ls
Makefile  mycal.c  process.c
[HJM@hjmlcc ~]$ local_val=hello     //本地(普通)变量、
[HJM@hjmlcc ~]$ echo $local_val
hello
[HJM@hjmlcc ~]$ 

//问:
//由上可知,变量loacl_val是本地(普通)变量,echo指令也是可执行程序,运行(使用)他的时候将会启动一个
//进程,而在Linux命令行中启动的进程的父进程都是bash进程,所以通过指令echo $local_val得到的进程
//是bash进程的子进程,我们又知道,对于普通(本地)变量local_val而言,是定义在bash进程内部的,并且本
//地(普通)变量不能被子进程继承,那么为什么通过指令echo $local_val得到的进程(bash进程的子进程)
//能够读取到该本地(普通)变量local_val的值并将其打印在屏幕上的呢?

//答:
//在Linux操作系统中,在Linux命令行中运行的指令大部分都是以bash进程的子进程(先创建子进程,让子进
//程完成这些指令相对应的功能)的方式执行的,但是还存在一部分在Linux命令行中运行的指令并不是通
//过bash进程的子进程的方式进行执行的,而是由bash进程自己运行(不会创建子进程,而是bash进程直接调
//用自己对应的函数来完成特定的功能),比如指令:echo,set,exoprt,cd等等,我们称这类指令为内建命令,
//即一些bash进程非常信任的命令,此时bash进程并不会通过其子进程帮其运行这些命令,而是bash进程自己
//运行这些命令,对于指令:set | grep local_val的原理也是如上、

补充:关于指令:export  cd 为什么是内建命令的原因请见视频:

进程地址空间:00:23:00 - 00:26:10、

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/155643.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【记录二】图层添加+坐标系转换理论+dva理论

坐标系一、坐标系地理坐标系cesium中的几种坐标系代码封装二、网页通讯模块PWAServiceWorker三、代码四、dva理论知识dva定义从redux -> dva带model的代码结构带model的数据流图一、坐标系 地理坐标系 cesium中的几种坐标系 链接: Cesium中的几种坐标和相互转换 代码封装…

Flowable进阶学习(一)表结构、ProcessEngine、Service、BPMN图标

文章目录一、Flowable表结构1.表结构讲解二、ProcessEngine讲解2.1 加载默认的配置文件2.2 加载自定义配置文件2.3 ProcessEngine源码2.4 ProcessEngineConfiguration中的init()方法2.5 ProcessEngine各种方式对比三、Service服务接口3.1 Service创建方式与名称作用简介四、Flo…

mysql核心知识-----索引

文章目录索引的概念和用途应用层的mysql&#xff08;各种操作语句&#xff09;与底层的mysql数据库&#xff08;磁盘上的文件&#xff09;交互IO的单位深入理解索引聚簇索引 VS 非聚簇索引普通&#xff08;辅助&#xff09;索引什么字段适合做主键&#xff1f;索引的概念和用途…

1.ISAAC简介

ISAAC简介 ISAAC教程合集地址: https://blog.csdn.net/kunhe0512/category_12163211.html Isaac 是 NVIDIA 的智能机器人开放平台。 Isaac SDK 提供了大量强大的 GPU 加速算法 GEM&#xff0c;用于导航和操作。 Isaac SDK Engine 是一个框架&#xff0c;可以轻松编写模块化应…

Android开发应用案例——简易计算器(附完整源码)

Android开发-AS学习&#xff08;一&#xff09;Android开发-AS学习&#xff08;二&#xff09;使用android studio开发简易计算器app&#xff08;完整源码可在博主资源中自行下载&#xff09;最终效果&#xff1a;开发步骤&#xff1a;创建一个名为calculator的新项目编写代码项…

Java加解密(六)基于口令(PBE)加密

目录基于口令&#xff08;PBE&#xff09;加密1 定义2 加密过程3 解密过程5 PBE加密算法会话密钥保存4 使用场景5 JDK支持的PBE加密算法6 Bouncy Castle 支持的PBE加密算法7 算法调用示例基于口令&#xff08;PBE&#xff09;加密 1 定义 PBE&#xff08;Password Based Encr…

linux文件管理和用户管理(二)

1、学习linux的原因&#xff1a; linux是一些做项目运维的工作人员用到最多的一个工具普通程序员学习linux的目的是为了让项目部署到服务器上&#xff0c;而大多数服务器都是linux系统&#xff08;centOS&#xff09;&#xff0c;所以对Linux要有基本的使用能力。 2、文件系统…

Python采集专栏文档保存成pdf

前期准备 环境使用 Python 3.8Pycharm 模块使用 requests >>> pip install requests 数据请求parsel >>> pip install parsel 数据解析re >>> 内置模块 不需要安装 正则表达式pdfkit >>> pip install pdfkit 实现步骤 采集文章内容,…

【前端】Vue项目:旅游App-(12)home-Calendar:日期选择、日历、动态显示时间

文章目录目标过程与代码安装依赖结构样式动态数据&#xff1a;默认数据今天明天添加日历修改样式动态数据&#xff1a;显示日历中选择的数据效果总代码修改或添加的文件formatDate.jshome.vuemain.js目标 点击时间&#xff1a; 弹出日历供选择&#xff1a; 动态显示数据&#…

Linux设备树简析

1. 前言 限于作者能力水平&#xff0c;本文可能存在谬误&#xff0c;因此而给读者带来的损失&#xff0c;作者不做任何承诺。 2. 设备树的来源 在 Linux 中&#xff0c;每个设备驱动&#xff0c;管理一组设备数据&#xff0c;类似面向对象编程中类和其实例对象的关系。一段时…

视频播放破亿,抖音近期的流量密码是什么

纵观12月抖音涨粉趋势&#xff0c;美食、医疗健康、生活日常等细分领域中涌现出不少优质账号&#xff0c;圈粉不断。从『粉丝飙升榜』TOP30来看&#xff0c; 12月上榜达人的更替率高达76.6%&#xff0c;向太陈岚单日涨粉557.26w&#xff0c;12月共收获751.09w粉丝&#xff0c;空…

做好网络舆情监测监控的重要性,TOOM网络舆情监控平台建设方案?

舆情监控在当今时代非常重要&#xff0c;互联网走进千家万户&#xff0c;各种信息在网络上传播&#xff0c;舆情监控旨在帮助公司了解公众对其产品、服务、品牌形象等的看法&#xff0c;并及时采取应对措施。接下来简单了解做好网络舆情监测监控的重要性&#xff0c;TOOM网络舆…

关于城市轨道交通的电力监控中心调度系统研究

摘 要 &#xff1a;在城市轨道交通的运行过程中&#xff0c;电力监控系统很好地监控了各个配电所、电力设备以及接触网等的运行情况&#xff0c;这对于城市轨道交通的安全稳定运行有着关键性的作用。因此&#xff0c;随着当今城市轨道交通事业的不断发展&#xff0c;城市轨道交…

MATLAB | 如何使用MATLAB绘制序列logo图

这次开发了一个生物信息学比较常用的序列logo图绘制MATLAB代码包&#xff0c;绘制效果如下&#xff1a; 数据来自基迪奥生物项目编号为seqlogojrois9l2jit的示例数据。同时本工具函数参考以下文献&#xff1a; Tareen A, Kinney J B. Logomaker: beautiful sequence logos in …

再见2022,你好2023:八年程序媛老兵的践行、思考与展望

再见2022&#xff0c;你好2023写在前面的话1.2022速记1.1 产假前&#xff0c;ParaView三维自动化项目1.2 产假后&#xff0c;EDA仿真项目1.3 从EDA行业谈谈2022年的经济寒冬2. 2023年的新年flag2.1 flag one:挑战高薪2.2 flag two:读更多的书&#xff0c;读更多专业书2.2.1 读过…

动态内存管理题目讲解

前言&#xff1a; 上一期我们讲述了有关动态内存管理的知识点&#xff0c;这期我们通过几个经典的笔试题来进行深入的了解以及对知识点的巩固 目录第一题第二题第三题第四套第一题 试题如下&#xff1a; void GetMemory(char* p) {p (char*)malloc(100); } void Test(void) …

1.H3CNE-计算机网络概述

计算机网络概述计算机网络定义一组自治计算机互联的集合计算机网络基本功能资源共享综合信息服务分布式处理与负载均衡计算机网络的类型局域网LAN&#xff08;Local Area Network) 由用户自行建设&#xff0c;使用私有地址组建的网络城域网MAN(Metropolitan Area Network)由运营…

为什么职场第一开发语言会是SQL?看完这些你就瞬间明白了

看到一个有趣的比喻&#xff0c;用来说明SQL与Excel的差别是什么。 如果把SQL比作火车&#xff0c;把Excel更比作卡车。 卡车灵活自由&#xff0c;高速或乡村小道想去哪就去哪&#xff0c;但即便每天不停歇卡车的运载量也不大&#xff0c;而且容易出交通事故。 火车运载量大…

windows下软件安装:miniconda下安装R4.1.3并将其添加到 Jupyter notebook 中

0. 说明&#xff1a; 本来是想在windows中用conda安装R&#xff0c;然后再下载安装RStudio并对其进行配置使之可以用conda环境中的R&#xff0c;但是经过尝试以及网络上查找相关文档发现&#xff0c;原版RStudio不支持使用conda环境中的R&#xff08;可能Anaconda中自带的RStu…

Visual studio C++桌面应用程序添加外部文件引用

C桌面应用程序添加外部文件引用 前言 之前对C的开发接触很少&#xff0c;本章节记录一下Visual studio开发C桌面应用程序是如何引入外部文件 ★提高阅读体验★ &#x1f449; ♠一级标题 &#x1f448; &#x1f449; ♥二级标题 &#x1f448; &#x1f449; ♥ 三级标…