# 前言

在了解 Linux 的环境变量前,我们先了解一下变量。

在脚本中使用以下代码

cyan@cyan-virtual-machine:~/Templates$ cat test
#!/bin/bash
val=10
while echo val
do
        echo " testing... "
done
#会循环打印:
#val
#testing...

在脚本中我们直接定义一个变量,该怎么用呢?直接在终端定义变量,此时变量是什么?

# 环境变量

划分为局部和全局变量,局部变量只对创建他们的 shell 可见,系统环境变量基本都是大写字母,区别于普通用户的环境变量,查看全局变量可以使用命令 env 或者 printenv

查看单个变量的值: printenv $HOME 或者 echo $HOME 。这里给出几个常见的系统环境变量

cyan@cyan-virtual-machine:~/Templates$ echo $HOME
/home/cyan
cyan@cyan-virtual-machine:~/Templates$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
cyan@cyan-virtual-machine:~/Templates$ echo $SHELL
/bin/bash

你可以把变量前面的美元符号 $ 看作取值,在变量前加上 $ 可以区分它到底是变量还是字符串。

cyan@cyan-virtual-machine:~/Templates$ echo $SHELL
/bin/bash
cyan@cyan-virtual-machine:~/Templates$ echo SHELL
SHELL

我们要定义自己的变量,直接定义即可

# 通过 cat 命令查看 test 文件内容
cyan@cyan-virtual-machine:~/Templates$ cat test
#!/bin/bash
val=10
echo val
# 自定义变量 value
cyan@cyan-virtual-machine:~/Templates$ value=./test
#尝试使用 value 来运行./test
cyan@cyan-virtual-machine:~/Templates$ value
value: command not found
#尝试使用 value 的值来运行./test,但是打印出来的不是 10,而是 val
cyan@cyan-virtual-machine:~/Templates$ $value
val
#可见,在脚本中,变量前也需要使用 $

看到这里你应该对变量有了大概的了解。 $ 相当于取出变量的值,想要定义一个变量,直接定义即可。但是这里有个致命的坑,我们平时写代码,为了有较高的可读性,一般在变量和 = 以及值之间都会加上空格,但是这在终端里面是致命的错误

cyan@cyan-virtual-machine:~/Templates$ val = 10
Command 'val' not found, did you mean:
  command 'pal' from deb pal (0.4.3-8.1build4)
  command 'cal' from deb bsdmainutils (11.1.2ubuntu3)
  command 'vala' from deb valac-bin (0.48.6-0ubuntu1)
  command 'fal' from deb dnet-progs (2.65build2)
  command 'vax' from deb simh (3.8.1-6)
  command 'al' from deb mono-devel (6.8.0.105+dfsg-2)
  command 'vam' from deb vim-addon-manager (0.5.10)
  command 'pval' from deb snacc (1.3.1-7build2)
  command 'vl' from deb atfs (1.4pl6-14)
Try: sudo apt install <deb name>

因为加上空格, shell (我的是 bash )就会认为,你的 val (变量名)是一个命令,空格后面的是该命令的参数。而 shell 没有找到 val 这个命令就会报错。

其实随着之后的学习,你会越来越理解 Linux 中各种设计的巧妙,我们调用的一个又一个命令(大部分),说穿了其实是一个又一个可执行文件,如果你之前在给 IDEAVsCode 这些工具配置环境变量时好好了解过到底为什么需要环境变量,那么你很清楚我刚才在说什么。

对于局部环境变量,bash 并没有什么指令可以单独显示, set 命令会显示为某个特定进程设置的所有环境变量,输出时会按照字母顺序排序

# 设置用户定义变量

上面已经讲得差不多了,这里再给出几个需要注意的点

  • 如果变量的值中含有空格,请使用用单(双)引号, val = "hello world"
  • 定义用户变量,请坚持使用小写字母。
  • 变量名,等号,值之间不能有空格。

# 设置全局环境变量

我们之前直接创建的变量是局部变量,对其他 shell (父子 shell )是不可见得。

cyan@cyan-virtual-machine:~/Templates$ var=10
cyan@cyan-virtual-machine:~/Templates$ bash
cyan@cyan-virtual-machine:~/Templates$ echo $var
cyan@cyan-virtual-machine:~/Templates$ exit
exit
cyan@cyan-virtual-machine:~/Templates$ echo $var
10

关于父子 shell ,我不会在这篇文章过多讲解,你要是求知心切,传送门

你现在可以这么理解, bash shell 也是一个程序,我们打开终端时, bash 也启动了,既然 bash 是程序,那我们在终端也可以运行 bash ,这样我们就处于子 shell父子 shell 使用不同的内存空间,所以在父 shell 创建的局部变量对子 shell 是不可见的。

创建全局环境变量的方法:先创建局部环境变量,再导出到全局变量

var='global'
export 'global' #export 就是导出命令,也可以直接导出:export var=global

子 shell 中修改全局变量不会影响父 shell 中该变量的值。根据该性质,在子 shell 中设置全局变量是没有意义的,因为其设置的值,根本不传给父 shell。

# 删除环境变量

unset var

解释:

  • 使用 unset 指令,可以直接删除变量,不需要加的本质是,得到环境变量的值!
  • printenv 指定了,传入的参数就是一个环境变量(自定义变量不行),可以直接使用。
  • 在子 shell 中对全局变量的修改无能反映到父 shell,哪怕是删除

# 设置 PATH 环境变量

PATH 环境变量定义了用于进行命令和程序查找的目录。

cyan@cyan-virtual-machine:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
  • 如果命令或程序位置没有包含在 PATH 中,如果不使用路径, shell 是没法找到并运行的。就像上一篇文章,我们必须使用 ./test.sh 才能运行该文件,使用 test.sh 是不行的。
  • 短暂的修改 PATH 命令就是: PATH=$PATH:. ,一般加 . 就是包含当前目录,当然也可以加其他路径。这种修改,在 exit 后会失效。
# 查看当前文件夹下文件
cyan@cyan-virtual-machine:~/Templates$ ls
new_File  test  test_1.sh
# 查看文件 test_1.sh 脚本内容 -- 打印 Hello World
cyan@cyan-virtual-machine:~/Templates$ cat test_1.sh
#!/bin/bash
echo "Hello World"
# 希望直接使用这个脚本名作为命令
cyan@cyan-virtual-machine:~/Templates$ test_1.sh
test_1.sh: command not found
# 将当前目录加到 PATH 中
cyan@cyan-virtual-machine:~/Templates$ PATH=$PATH:.
cyan@cyan-virtual-machine:~/Templates$ test_1.sh
Hello World

如果你还没明白,可以参考以下这个(我觉得和我讲的差不多)如何理解 PATH。如果还是不懂,真拿你没办法,就再给个 真正的传送门

# 最后

关于如何持久化创建一个环境变量,这涉及到修改一些系统文件,文件权限以及 shell 进程的一些知识,之后再说吧。