Skip to content

使用Linux环境变量

可以帮助提升Linuxshell的使用体验, 很多程序以及脚本都可以使用环境变量来获取系统信息, 存储临时的数据以及配置

什么是环境变量

bash shell用一个环境变量的特性来储存有关shell会话和工作环境的信息, 允许你在内存中存储数据, 以便程序、脚本可以找到

有两种环境变量

  • 全局变量
  • 局部变量

不同版本的Linux可能会有不同的环境变量, 可以从发行版文档上查看

全局环境变量

全局环境变量对于shell会话和所有的shell都是可见的, 局部变量则只是创建他的shell可见, 对于创建子shell需要父shell信息的时候有用

有很多的变量是在登陆的时候设置的, 登录的方式也会有影响

查看全局变量:

bash
$ printenv
$ env

要显示个别的环境变量可以使用printenv命令

C
jiao@jiao-virtual-machine:~/桌面$ printenv HOME
/home/jiao
jiao@jiao-virtual-machine:~/桌面$ env HOME
env: “HOME”: 没有那个文件或目录

也可以使用echo来显示某一个环境变量的值, 在变量名字之前加上$

bash
jiao@jiao-virtual-machine:~/桌面$ echo $HOME
/home/jiao

加上一个$可以让环境变量的值变成命令的参数

bash
jiao@jiao-virtual-machine:~/桌面$ ls $HOME
01_Python  公共的  模板  视频  图片  文档  下载  音乐  桌面  Makefile  snap

局部环境变量

局部变量只有在设置的进程可见, Linux定义了标准的环境变量, 但是你可以设置属于自己的局部变量, 叫做用户定义局部变量

没有专门显示局部变量的命令, set命令显示所有某一个特定进程的所有环境变量, 全局变量+局部变量+用户定义局部变量

说明命令env、printenv和set之间的差异很细微。set命令会显示出全局变量、局部变量以及用户定义变量。它还会按照字母顺序对结果进行排序。env和printenv命令同set命令的区别在于前两个命令不会对变量排序,也不会输出局部变量和用户定义变量。在这种情况下,env和printenv的输出是重复的。不过env命令有一个printenv没有的功能,这使得它要更有用一些

设置用户定义变量

可以直接在bash之中设置自己的变量

设置局部用户定义变量

一旦启动bash shell或一个bash脚本, 就能创建在这个进程shell内部可见的局部变量, 使用等号进行赋值, 可以是数字或字符串

bash
jiao@jiao-virtual-machine:~/桌面$ echo $my_varible

jiao@jiao-virtual-machine:~/桌面$ my_varible=Hello
jiao@jiao-virtual-machine:~/桌面$ echo $my_varible
Hello

只要使用$my_varible就可以使用

如果要给他一个有空格的字符串, 就要用双引号, 否则就会把第二个当做新的命令

bash
jiao@jiao-virtual-machine:~/桌面$ my_varible=hello ls
1.py  algorithm  begin.txt  c_langage  helloworld  helloworld_1.0_i386.deb  linux-shell  ll_env

所有的环境变量都使用大写, 但是在创建局部变量或者shell脚本的时候要使用小写

**注:**变量名、等号和值之间没有空格

设置的局部变量在子shell之中不能使用

设置全局的环境变量

设置的全局变量在所有的子程序之中都可以使用

设置的方法: 首先设置一个局部变量, 然后导出到全局变量, 使用export命令

bash
jiao@jiao-virtual-machine:~/桌面$ my_variable="I an jhy"
jiao@jiao-virtual-machine:~/桌面$ export my_variable
jiao@jiao-virtual-machine:~/桌面$ dash
$ echo my_variable
my_variable
$ echo $my_variable
I an jhy
$ exit

修改子shell中全局环境变量并不会影响到父shell中该变量的值

子shell甚至无法使用export命令改变父shell中全局环境变量的值

bash
jiao@jiao-virtual-machine:~$ my_variable="I am JHY"
jiao@jiao-virtual-machine:~$ export my_variable		//全局变量
jiao@jiao-virtual-machine:~$ bash                   //进入子shell
jiao@jiao-virtual-machine:~$ ps --forest
    PID TTY          TIME CMD
   2331 pts/0    00:00:00 bash
   2372 pts/0    00:00:00  \_ bash
   2379 pts/0    00:00:00      \_ ps
jiao@jiao-virtual-machine:~$ echo $my_variable		//可以读取
I am JHY
jiao@jiao-virtual-machine:~$ my_variable="NULL"		//更改
jiao@jiao-virtual-machine:~$ echo $my_variable
NULL
jiao@jiao-virtual-machine:~$ export my_variable		//设置为全局
jiao@jiao-virtual-machine:~$ exit
exit
jiao@jiao-virtual-machine:~$ echo $my_variable
I am JHY

删除环境变量

bash
jiao@jiao-virtual-machine:~$ echo $my_variable
I am JHY
jiao@jiao-virtual-machine:~$ unset my_variable
jiao@jiao-virtual-machine:~$ echo $my_variable

如果要用到变量,使用$;如果要操作变量,不使用$。这条规则的一个例外就是使用printenv显示某个变量的值

在处理全局环境变量时,如果你是在子进程中删除了一个全局环境变量,这只对子进程有效。该全局环境变量在父进程中依然可用。

默认的环境变量

有部分的环境变量和之前的Unix Bourne shell 兼容

还有一些自有的变量

不是每一个都会在set的时候列出, 也不是每一个都有对应的值

设置PATH环境变量

在shell输入一个外部命令的时候, shell搜索系统来找到对应的程序, PATH定义的路径就是查找的路径

bash
jiao@jiao-virtual-machine:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin

使用冒号分割, 如果命令或者程序没有保存在对应的路径, 就必须使用绝对路径来查找

bash
jiao@jiao-virtual-machine:~$ PATH=$PATH:/home/jiao/桌面
jiao@jiao-virtual-machine:~$ PATH=$PATH:.

把桌面以及当前目录加入到搜索列表

定位系统环境变量

已经知道了怎么实质环境变量, 下一步是进行永久保存

当你登陆一个Linux系统的时候, 默认情况下bash会在几个文件夹中查找命令, 这些文件夹叫启动文件夹或者环境文件, 检查的文件取决于登录的方式

  • 登录时作为默认登录的shell
  • 作为非登录的交互式shell
  • 作为运行脚本的非交互shell

登录shell

登陆的时候启动的bash shell会从五个不同的文件夹读取数据

  • /etc/profile
  • $HOME/.bash_profile
  • $HOME/.bashrc
  • $HOME/.bash_login
  • $HOME/.profile

/etc/profile是默认的bash shell主启动文件, 每一个用户都会调用

要留意的是有些Linux发行版使用了可拆卸式认证模块(Pluggable Authentication Modules ,PA M)。在这种情况下,PA M文件会在bash shell启动之前处理,这些文件中可能会包含环境变量。PA M文件包括/etc/environment文件和$HOME/.pam_environment文件。PA M更多的相关信息可以在http://linux-pam.org中找到

另外的四个文件是针对用户的, 可根据个人需求定制

/etc/profile文件

只要你登录就会执行其中的命令

启动文件中会使用for语句来迭代/etc/profile.d目录下的所有文件, 这为Linux系统提供了一个放置特定应用程序启动文件的地方

bash
jiao@jiao-virtual-machine:~/桌面$ ls /etc/profile.d/ -hl
总用量 40K
-rw-r--r-- 1 root root   96  2月 26  2021 01-locale-fix.sh
-rw-r--r-- 1 root root  835 10月  8  2021 apps-bin-path.sh
-rw-r--r-- 1 root root  726  9月  3  2020 bash_completion.sh
-rw-r--r-- 1 root root 1003  8月 13  2019 cedilla-portuguese.sh
-rw------- 1 root root  241 10月 13  2021 debuginfod.csh
-rw------- 1 root root  132 10月 13  2021 debuginfod.sh
-rw-r--r-- 1 root root  349 12月 18  2020 im-config_wayland.sh
-rw-r--r-- 1 root root 1.4K  6月 27  2021 vte-2.91.sh
-rw-r--r-- 1 root root  967  6月 27  2021 vte.csh
-rw-r--r-- 1 root root  954  9月 21  2021 xdg_dirs_desktop_session.sh

有些文件与系统中的特定应用有关。大部分应用都会创建两个启动文件:一个供bash shell使用(使用.sh扩展名),一个供c shell使用(使用.csh扩展名)

$HOME目录下的启动文件

剩下的启动文件都起着同一个作用, 提供一个用户的专属启动文件, 定义用户专用的环境变量

大多数的Linux只用四个启动文件的一到两个

  • $HOME/.bash_profile
  • $HOME/.bashrc
  • $HOME/.bash_login
  • $HOME/.profile

启动的顺序, 找到一个剩下的忽略

  • $HOME/.bash_profile

  • $HOME/.bash_login

  • $HOME/.profile

没有$HOME/.bashrc, 因为该文件通常通过其他文件来运行

交互式shell

不是系统启动的时候启动的shell, 那么你启动的shell叫做交互式shell, 他不会像登录的shell一样运行, 但是提供了命令行提示符来输入命令

如果是交互式shell启动的文件, 就不会访问/etc/profile只会检查用户HOME目录中的.bashrc文件

非交互式shell

系统执行shell脚本的时候, 没有命令提示符, 当你在系统上运行脚本时,也许希望能够运行一些特定启动的命令

为了处理这种情况,bash shell提供了BASH_ENV环境变量, 它会检查这个环境变量来查看要执行的启动文件, 这通常包括shell脚本变量设置

如果没有, 脚本的变量会来自, 父shell设置的变量

父shell设置但是没有导出的都是局部变量, 不能被继承

环境变量持久化

放在/etc/profile中会在系统升级的时候更改

最好在/etc/profile.d目录中创建一个.sh结尾的文件

储存个人用户的shell变量是~/.bashrc文件, 但如果设置了BASH_ENV变量,那么记住,除非它指向的是$HOME/.bashrc,否则你应该将非交互式shell的用户变量放在别的地方

图形化界面组成部分(如GUI客户端)的环境变量可能需要在另外一些配置文件中设置,这和设置bash shell环境变量的地方不一样

数组变量

环境变量可以当做数组使用, 数组可以存储多个变量, 这些值可以单独引用也可以整个使用

bash
jiao@jiao-virtual-machine:/home$ mytest=(one two three four five)
jiao@jiao-virtual-machine:/home$ echo ${mytest[2]}
three

可以使用通配符*, 显示所有的值

bash
jiao@jiao-virtual-machine:/home$ echo ${mytest[*]}
one two three four five

可以使用索引改变某一个位置的值

bash
jiao@jiao-virtual-machine:/home$ mytest[2]=seven
jiao@jiao-virtual-machine:/home$ echo ${mytest[2]}
seven

可以使用unset删除某个位置的值

bash
jiao@jiao-virtual-machine:/home$ unset mytest[2]
jiao@jiao-virtual-machine:/home$ echo ${mytest[*]}
one two four five
jiao@jiao-virtual-machine:/home$ echo ${mytest[2]}

jiao@jiao-virtual-machine:/home$