Linux环境变量
什么是环境变量
bash shell使用环境变量来存储shell会话和工作环境的相关信息(这也是被称作环境变量的原因)。
bash shell中有两种环境变量。
·全局变量
·局部变量
全局环境变量
全局环境变量对于shell会话和所有生成的子shell都是可见的。局部环境变量则只对创建它的shell可见。
可以使用env
命令或printenv
命令来查看全局变量:
[root@Wesuiliye ~]# env XDG_SESSION_ID=2998 HOSTNAME=Wesuiliye TERM=xterm-256color SHELL=/bin/bash HISTSIZE=1000 SSH_CLIENT=111.111.111.11 42623 22 SSH_TTY=/dev/pts/2 JRE_HOME=/data/jdk-19.0.2+7/jre ......
[root@Wesuiliye ~]# printenv XDG_SESSION_ID=2998 HOSTNAME=Wesuiliye TERM=xterm-256color SHELL=/bin/bash HISTSIZE=1000 SSH_CLIENT=111.111.111.11 42623 22 SSH_TTY=/dev/pts/2 JRE_HOME=/data/jdk-19.0.2+7/jre USER=root
要显示个别环境变量的值,可以使用printenv
命令,但不要使用env
命令:
[root@Wesuiliye ~]# printenv HOME /root [root@Wesuiliye ~]# env HOME env: HOME: No such file or directory
也可以使用echo命令显示变量的值。在引用某个环境变量时,必须在该变量名前加上美元符号($):
[root@Wesuiliye ~]# echo $HOME /root
在变量名前加上$ 它还能让变量作为其他命令的参数:
[root@Wesuiliye ~]# ll $HOME total 20 -rw-r--r-- 1 root root 0 Apr 29 22:26 123 drwxr-xr-x 2 root root 4096 May 1 00:11 data drwxr-xr-x 2 root root 4096 Apr 28 18:24 java drwxr-xr-x 3 root root 4096 Apr 28 18:28 MCserver drwxr-xr-x 3 root root 4096 Apr 9 09:55 New_dir drwxr-xr-x 6 root root 4096 Apr 22 10:21 Nonebot
局部环境变量
顾名思义,局部环境变量只能在定义它的进程中可见。
定义自己的局部变量,这些变量被称为用户自定义局部变量。
没有那条指令可以只显示局部变量,set命令可以显示特定进程的所有环境变量,既包括局部变量、全局变量,也包括用户自定义变量:
[root@Wesuiliye ~]# set | tail { local quoted=${1//\'/\'\\\'\'}; printf "'%s'" "$quoted" } quote_readline () { local quoted; _quote_readline_by_ref "$1" ret; printf %s "$ret" } [root@Wesuiliye ~]#
设置用户自定义变量
可以在bash shell中直接设置自己的变量
设置局部用户自定义变量
启动bash shell(或者执行shell脚本)之后,就能创建仅对该shell进程可见的局部用户自定义变量。可以使用等号为变量赋值,值可以是数值或字符串:
[root@Wesuiliye ~]# my_variable=Hello [root@Wesuiliye ~]# echo $my_variable Hello [root@Wesuiliye ~]#
如果用于赋值的字符串包含空格,则必须用单引号或双引号来界定该字符串的起止:
[root@Wesuiliye ~]# my_variable=Hello World bash: World: command not found... [root@Wesuiliye ~]# my_variable="Hello World" [root@Wesuiliye ~]# echo $my_variable Hello World [root@Wesuiliye ~]#
如果没有引号,则bash shell会将下一个单词[插图](World)视为另一个要执行的命令。注意,你定义的局部变量用的是小写字母,而系统环境变量用的都是大写字母。
变量名区分大小写。坚持使用小写字母命名用户自定义的局部变量,能够让你避免不小心与系统环境变量同名可能带来的灾难。
在变量名、等号和值之间没有空格。如果在赋值表达式中加上了空格,那么bash shell会将值视为单独的命令:
[root@Wesuiliye ~]# my_variable = "Hello World" bash: my_variable: command not found... [root@Wesuiliye ~]#
设置好局部变量后,就能在shell进程中随意使用了。但如果又生成了另一个shell,则该变量在子shell中不可用:
[root@Wesuiliye ~]# my_variable="Hello World" [root@Wesuiliye ~]# echo $my_variable Hello World [root@Wesuiliye ~]# bash [root@Wesuiliye ~]# echo $my_variable [root@Wesuiliye ~]# exit exit [root@Wesuiliye ~]# echo $my_variable Hello World [root@Wesuiliye ~]#
如果在子进程中设置了一个局部变量,那么一旦退出子进程,该局部变量就不能用了
设置全局环境变量
全局环境变量在设置该变量的父进程所创建的子进程中都是可见的。创建全局环境变量的方法是先创建局部变量,然后再将其导出到全局环境中。
这可以通过export
命令以及要导出的变量名(不加$符号)来实现:
[root@Wesuiliye ~]# my_variable="I am Global now" [root@Wesuiliye ~]# export my_variable [root@Wesuiliye ~]# echo $my_variable I am Global now [root@Wesuiliye ~]# bash [root@Wesuiliye ~]# echo $my_variable I am Global now [root@Wesuiliye ~]# exit exit [root@Wesuiliye ~]# echo $my_variable I am Global now [root@Wesuiliye ~]#
以将设置变量和导出变量放在一个命令里完成。
[root@Wesuiliye ~]# export my_variable="I am Global now" [root@Wesuiliye ~]# echo $my_variable I am Global now [root@Wesuiliye ~]#
修改子shell中的全局环境变量并不会影响父shell中该变量的值:
[root@Wesuiliye ~]# export my_variable="I am Global now" [root@Wesuiliye ~]# echo $my_variable I am Global now [root@Wesuiliye ~]# [root@Wesuiliye ~]# bash [root@Wesuiliye ~]# echo $my_variable I am Global now [root@Wesuiliye ~]# my_variable="NULL" [root@Wesuiliye ~]# echo $my_variable NULL [root@Wesuiliye ~]# exit exit [root@Wesuiliye ~]# echo $my_variable I am Global now [root@Wesuiliye ~]#
这种改变仅在子shell中有效,并不会反映到父shell环境中。子shell甚至无法使用export命令改变父shell中全局环境变量的值
删除环境变量
既然可以创建新的环境变量,自然也能删除已有的环境变量。可以用unset
命令来完成这个操作。在unset命令中引用环境变量时,记住不要使用$。
[root@Wesuiliye ~]# export my_variable="I am Global now" [root@Wesuiliye ~]# echo $my_variable I am Global now [root@Wesuiliye ~]# unset my_variable [root@Wesuiliye ~]# echo $my_variable [root@Wesuiliye ~]#
提示 在涉及环境变量名时,什么时候该使用$,什么时候不该使用$,实在让人摸不着头脑。只需记住一点:如果要用到(doing anything with)变量,就使用$;如果要操作(doing anything to)变量,则不使用$。这条规则的一个例外是使用printenv显示某个变量的值。
如果是在子进程中删除了一个全局环境变量,那么该操作仅对子进程有效。该全局环境变量在父进程中依然可用:
[root@Wesuiliye ~]# export my_variable="i am Global now" [root@Wesuiliye ~]# echo $my_variable i am Global now [root@Wesuiliye ~]# bash [root@Wesuiliye ~]# echo $my_variable i am Global now [root@Wesuiliye ~]# unset my_variable [root@Wesuiliye ~]# echo $my_variable [root@Wesuiliye ~]# exit exit [root@Wesuiliye ~]# echo $my_variable i am Global now [root@Wesuiliye ~]#
和修改变量一样,在子shell中删除全局变量后,无法将效果反映到父shell中。
默认的shell环境变量
查看bash版本
bash --version 或 echo $BASH_VERSION
当前bash进程号
echo $BASHPID
当前用户的有效用户ID
echo $EUID
shell查找命令时使用的目录列表
echo $PATH
设置PATH环境变量
当你在shell CLI中输入一个外部命令时,shell必须搜索系统,从中找到对应的程序。PATH环境变量定义了用于查找命令和程序的目录。
[root@Wesuiliye ~]# echo $PATH /data/jdk-19.0.2+7/bin:/data/python38/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/.local/bin:/root/bin:/root/.local/bin
如果命令或者程序所在的位置没有包括在PATH变量中,那么在不使用绝对路径的情况下,shell是无法找到的。
添加到现有的PATH环境变量中,无须从头定义。PATH中各个目录之间以冒号分隔。只需引用原来的PATH值,添加冒号(:),然后再使用绝对路径输入新目录即可。
[root@Wesuiliye ~]# PATH=$PATH:/root/123 [root@Wesuiliye ~]# echo $PATH /data/jdk-19.0.2+7/bin:/data/python38/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/.local/bin:/root/bin:/root/.local/bin:/root/.local/bin:/root/123
1.如果希望程序位置也可用于子shell,则务必确保将修改后的PATH环境变量导出。
2.对于PATH变量的修改只能持续到退出或重启系统。这种效果并不能一直奏效
定位系统环境变量
当登录Linux系统启动bash shell时,默认情况下bash会在几个文件中查找命令。这些文件称作启动文件或环境文件。bash进程的启动文件取决于你启动bash shell的方式。
启动bash shell有以下3种方式:
·登录时作为默认登录shell;
·作为交互式shell,通过生成子shell启动;
·作为运行脚本的非交互式shell。
登录shell
bash shell会作为登录shell启动。登录shell通常会从5个不同的启动文件中读取命令。
·/etc/profile ·$HOME/.bash_profile ·$HOME/.bashrc ·$HOME/.bash_login ·$HOME/.profile
/etc/profile文件是系统中默认的bash shell的主启动文件。系统中的每个用户登录时都会执行这个启动文件。
1./etc/profile文件
/etc/profile文件是bash shell默认的主启动文件。只要登录Linux系统,bash就会执行/etc/profile启动文件中的命令。
[root@Wesuiliye ~]# cat /etc/profile | tail PATH=/data/python38/bin:$PATH export PATH export JAVA_HOME=/data/jdk-19.0.2+7 export JRE_HOME=${JAVA_HOME}/jre export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib export PATH=${JAVA_HOME}/bin:$PATH [root@Wesuiliye ~]# cat /etc/profile | ta tabs tail tapestat targetcli targetctl tac tailf tar targetclid taskset [root@Wesuiliye ~]# cat /etc/profile | tail PATH=/data/python38/bin:$PATH export PATH export JAVA_HOME=/data/jdk-19.0.2+7 export JRE_HOME=${JAVA_HOME}/jre export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib export PATH=${JAVA_HOME}/bin:$PATH
2.$HOME目录下的启动文件
其余的启动文件都用于同一个目的:提供用户专属的启动文件来定义该用户所用到的环境变量。
·$HOME/.bash_profile ·$HOME/.bashrc ·$HOME/.bash_login ·$HOME/.profile
注意,这些文件都以点号开头,说明属于隐藏文件(不会出现在一般的ls命令输出中)。
shell会按照下列顺序执行第一个被找到的文件,余下的则被忽略。
·$HOME/.bash_profile ·$HOME/.bash_login ·$HOME/.profile
1.Linux发行版在环境文件方面存在的差异非常大。$HOME文件下的那些文件并非每个用户都有。例如,有些用户可能只有一个$HOME/.bash_profile文件。这很正常。
2..bash_profile启动文件会先检查$HOME目录中是不是还有一个名为.bashrc的启动文件。如果有,就先执行该文件中的命令。
交互式shell进程
如果不是在登录系统时启动的bash shell(比如在命令行中输入bash),那么这时的shell称作交互式shell。
作为交互式shell启动的bash并不处理/etc/profile文件,只检查用户$HOME目录中的.bashrc文件。
[root@Wesuiliye ~]# cat .bashrc # .bashrc # User specific aliases and functions alias rm='rm -i' alias cp='cp -i' alias mv='mv -i' # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi # Created by `pipx` on 2023-04-08 08:09:13 export PATH="$PATH:/root/.local/bin"
.bashrc文件会做两件事:首先,检查/etc目录下的通用bashrc文件;其次,为用户提供一个定制自己的命令别名和脚本函数的地方。
非交互式shell
最后一种shell是非交互式shell。系统执行shell脚本时用的就是这种shell。不同之处在于它没有命令行提示符。
脚本能以不同的方式执行。只有部分执行方式会启动子shell。
为了处理这种情况,bash shell提供了BASH_ENV环境变量。当shell启动一个非交互式shell进程时,会检查这个环境变量以查看要执行的启动文件名。如果有指定的文件,则shell会执行该文件里的命令,这通常包括shell脚本变量设置。
如果父shell是登录shell,在/etc/profile
文件、/etc/profile.d/*.sh
文件和$HOME/.bashrc
文件中设置并导出了变量,那么用于执行脚本的子shell就能继承这些变量。
任何由父shell设置但未导出的变量都是局部变量,不会被子shell继承。
环境变量持久化
在/etc/profile.d
目录中创建一个以.sh结尾的文件。把所有新的或修改过的全局环境变量设置都放在这个文件中。
保存个人用户永久性bash shell变量的最佳地点是$HOME/.bashrc
文件。
数组变量
数组是能够存储多个值的变量。这些值既可以单独引用,也可以作为整体引用。
要为某个环境变量设置多个值,可以把值放在圆括号中,值与值之间以空格分隔:
[root@Wesuiliye ~]# mytest=(zero ont two three four) [root@Wesuiliye ~]# echo $mytest zero [root@Wesuiliye ~]#
以上代码只显示了数组的第一个值。要引用单个数组元素,必须使用表示其在数组中位置的索引。索引要写在方括号中,$符号之后的所有内容都要放入花括号中。
[root@Wesuiliye ~]# echo ${mytest[2]} two [root@Wesuiliye ~]#
环境变量数组的索引都是从0开始的。
要显示整个数组变量,可以用通配符*作为索引:
[root@Wesuiliye ~]# echo ${mytest[*]} zero ont two three four [root@Wesuiliye ~]#
也可以改变某个索引位置上的值:
[root@Wesuiliye ~]# mytest[2]=seven [root@Wesuiliye ~]# echo ${mytest[*]} zero ont seven three four [root@Wesuiliye ~]#
用unset命令来删除数组中的某个值
[root@Wesuiliye ~]# unset mytest[2] [root@Wesuiliye ~]# echo ${mytest[*]} zero ont three four [root@Wesuiliye ~]# echo ${mytest[2]} [root@Wesuiliye ~]# echo ${mytest[3]} three [root@Wesuiliye ~]#
显示整个数组变量,看上去是填充了2的位置,但是专门显示索引2位置上的值时,你会发现这个位置是空的。
可以在unset命令后跟上数组名来删除整个数组:
[root@Wesuiliye ~]# unset mytest [root@Wesuiliye ~]# echo ${mytest[*]} [root@Wesuiliye ~]#
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律