Linux环境变量

1. 什么是shell?

答:在计算机科学中,Shell俗称壳(用来区别于核,核是指“内核”),Shell是指“提供使用者使用界面”的软件(命令解析器)。它类似于DOS下的command.com和后来的cmd.exe。它接收用户命令,然后调用相应的应用程序。

在很多并不正式的场合,这两个名词表达的意思相同,即命令解释器。但从严格的意义上讲,命令行是指供用户输入命令的界面,其本身只是接受输入,然后把命令传递给命令解释器,后者就是Shell,从本质上讲,Shell是一个程序,它在用户和操作系统之间提供了一个面向行的可交互接口,用户在命令行中输入命令,运行在后台的Shell把命令转换成指令代码发送给操作系统。Shell并非只有命令行这一种形式,例如GNOME、KDE等图形界面也是Shell,不过它们是GUI Shell,都是为了解决人机交互的问题。

目前在Linux环境下有几种不同类型的Shell,常用的有Bourne Again Shell(BASH)、TCSH Shell、Z-Shell。不同的Shell提供不同的语法和特性。

例如在Ubuntu中,可以在etc/passwd文件中查看到自己的默认shell程序,如下所示:

1
2
biotest@ubuntu:~$ cat /etc/passwd |grep biotest
biotest:x:1000:1000:UBUNTU,,,:/home/biotest:/bin/bash

由上述结果可知,biotest用户所用到shell是bash。bash shell程序位于/bin目录内,从长列表中可以看出/bin/bash是一个可执行程序:

1
2
biotest@ubuntu:~$ ls -lF /bin/bash
-rwxr-xr-x 1 root root 1037528 May 16 2017 /bin/bash*

注:在Linux系统中,当使用ls,添加了-F参数时,会在每个输出项后追加文件的类型标识符,具体含义为:“*”表示具有可执行权限的普通文件,“/”表示目录,“@”表示符号链接,“|”表示命令管道FIFO,“=”表示sockets套接字。当文件为普通文件时,不输出任何标识符;

2. 什么是bash?

答:bash相当于shell中的某个,shell的范围更广。bash的全称是Bourne again / born again。

3. 什么是环境变量?

答:shell 在 shell 会话中保存着大量信息。这些信息被称为 (shell 的) 环境。 程序获取环境中的数据(即环境变量)来了解本机的配置。虽然大多数程序用配置文件来存储程序设置, 一些程序会根据环境变量来调整他们的行为。Linux是一个多用户的操作系统。每个用户登录系统后,都会有一个专用的运行环境。 通常每个用户默认的环境都是相同的,这个默认环境实际上就是一组环境变量的定义。 环境变量是全局的,设置好的环境变量可以被所有当前用户所运行的程序所使用。 用户可以对自己的运行环境进行定制,其方法就是修改相应的系统环境变量。在bash shell中,环境变量分为两类,分别为全局变量,局部变量。

shell 在环境中存储了两种基本类型的数据,虽然 bash 几乎无法分辨这些数据的类型。 它们是环境变量和 shell 变量。Shell 变量是 bash 存放的少量数据。剩下的都是 环境变量。除了变量,shell 也存储了一些可编程的数据,即别名和 shell 函数。

4. 如何查看环境变量?

答:printenv可以显示全局变量,如下所示:

mark
上述的内容是环境变量及其数值列表,环境变量通常是大写字母,这主要是为了与用户的变量进行区分,例如我们可以看到USER=biotest这行代码,就表示当前的用户是biotest,用printenv命令也可以查看当前用户,如下所示:

biotest@ubuntu:~$ printenv USER
biotest

通过echo来查看变量的值,如下所示:

1
2
3
4
biotest@ubuntu:~$ echo $HOME
/home/biotest
biotest@ubuntu:~/miniconda2/opt$ echo $PWD # PWD是显示当前目录
/home/biotest/miniconda2/opt

$的作用

在echo命令中,在变量名前加上$就能显示当前变量的值,它也能让变量作为命令行参数,如下所示:

1
2
3
4
biotest@ubuntu:~/miniconda2/opt$ ls $HOME
biosoft Downloads Miniconda2-latest-Linux-x86_64.sh Public Videos
Desktop examples.desktop Music Templates
Documents miniconda2 Pictures test

设置局部用户定义变量

一旦启动了bash shell(或者执行一个shell脚本),就能创建在这个shell进程内可见的局部变量了。可以通过等号给环境变量赋值,值可以是数值或字符串,需要注意的是,在shell中,变量名,等号和值之间没有空格,否则会出错,如下所示:

1
2
3
4
5
biotest@ubuntu:~/miniconda2/opt$ echo $mywords
biotest@ubuntu:~/miniconda2/opt$ mywords=hello
biotest@ubuntu:~/miniconda2/opt$ echo $mywords
hello

如果要给变量赋值一个含有空格的字符串,必须要加上单绰号来界定字符串的首和尾,如下所示:

1
2
3
4
5
biotest@ubuntu:~/miniconda2/opt$ mywords=Hello linux
linux: command not found
biotest@ubuntu:~/miniconda2/opt$ mywords="Hello linux"
biotest@ubuntu:~/miniconda2/opt$ echo $mywords
Hello linux

设置了局部变量后,就能在shell进程的任何地方使用它了,但是,如果生成了另外一个shell,在它的子shell中就无法使用。类似地,如果在子进程中设置了一个局部变量,一旦退出了子进程,那个局部环境变量就无法使用。

设置全局环境变量

在设定全局环境变量的进程所创建的子进程中,该变量都是可见的。创建全局环境变量的方法是先创建一个局部环境变量,然后再把它导出到全局环境中。,这个过程是通过export命令实现的,变量名前面不加$,如下所示:

1
2
3
4
5
6
7
biotest@ubuntu:~$ my_words="I love Linux"
biotest@ubuntu:~$ export my_words
biotest@ubuntu:~$ echo $mywords
Hello linux
biotest@ubuntu:~$ bash
bbiotest@ubuntu:~$ echo $my_words
I love Linux

在定义了my_words变量后,用bash命令启动了一个子shell,在空上子shell中能够显示变量my_words的值,这是因为export命令将其设为了全局变量。

修改子shell中全局环境变量的值并不会影响你shell中该变量的值,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
biotest@ubuntu:~$ echo $my_words
I love Linux
biotest@ubuntu:~$ bash
biotest@ubuntu:~$ echo $my_words
I love Linux
biotest@ubuntu:~$ my_words="I love Ubuntu"
biotest@ubuntu:~$ echo $my_words
I love Ubuntu
biotest@ubuntu:~$ exit
exit
biotest@ubuntu:~$ exit
exit
biotest@ubuntu:~$ ps
PID TTY TIME CMD
20142 pts/4 00:00:00 bash
20318 pts/4 00:00:00 ps
biotest@ubuntu:~$ echo $my_words
I love Linux

子shell也无法通export命令改变父shell中全局变量的值。

删除环境变量

删除环境变量使用unset命令,前面不加$符号,如下所示:

1
2
3
4
5
6
biotest@ubuntu:~$ echo $my_words
I love Linux
biotest@ubuntu:~$ unset my_words
biotest@ubuntu:~$ echo $my_words
biotest@ubuntu:~$

在涉及变量名时,什么时候使用,只需要这样记忆:要具体地查看变量的值时,就需要符号。

5. setprintenv都可以查看系统变量,它们有什么区别?

答:(1)通过set可以设置shell选项,如果只输入set而不加任何参数,它就会显示shell 变量,环境变量,和定义的 shell 函数,此时与printenv命令类似,与 printenv 命令不同的是,set 命令的输出很友好地按照首字母顺序排列,如下所示:

mark
如上图所示,当使用没有带选项和参数的 set 命令时,shell 变量,环境变量,和定义的 shell 函数都会被显示。不同于 printenv 命令,set 命令的输出很友好地按照首字母顺序排列。
(2)set命令显示当前shell的变量,包括当前用户的变量;printenv(输入env也可以)命令只显示当前用户的变量。每个shell有自己特有的变量(set)显示的变量,这个和用户变量是不同的,当前用户变量和你用什么shell无关,不管你用什么shell都在,比如HOME,SHELL等这些变量,但shell自己的变量不同shell是不同的,比如BASH_ARGC, BASH等,这些变量只有set才会显示,是bash特有的。

6. 环境变量存放在哪个地方?

答:当你进入系统的时候,linux 就会为你读入系统的环境变量,这些环境变量存放在什么地方,那就是环境变量的文件中。Linux 中有很多记载环境变量的文件,它们被系统读入是按照一定的顺序的,这些文件包括以下部分:

6.1 /etc/profile

此文件是bash shell默认的主启动文件,只要登录了Linux,bash就会执行/etc/profile启动文件中的命令,该文件存储的是整个系统的环境变量,它为每个用户设置环境信息,这个文件只有root才能修改。当用户第一次登录时,该文件被执行。并从/etc/profile.d目录的配置文件中搜集shell 的设置。这个文件,是任何用户登陆操作系统以后都会读取的文件(如果用户的shell 是csh 、tcsh 、zsh ,则不会读取此文件),用于获取系统的环境变量,只在登陆的时候读取一次。

6.2/etc/bashrc

在执行完/etc/profile 内容之后,如果用户的Shell运行的是bash ,那么接着就会执行此文件。另外,当每次一个新的bash shell 被打开时, 该文件被读取。每个使用bash的用户在登陆以后执行完/etc/profile 中内容以后都会执行此文件,在新开一个bash 的时候也会执行此文件。因此,如果你想让每个使用bash 的用户每新开一个bash 和每次登陆都执行某些操作,或者给他们定义一些新的环境变量,就可以在这个里面设置。
注:/etc/profile/etc/bashrc 是系统全局环境变量设定

6.3$HOME/.bashrc

该文件包含专用于单个人的bash shell 的bash 信息,当登录时以及每次打开一个新的shell 时, 该该文件被读取。 单个用户此文件的修改会影响到他以后的每一次登陆系统和每一次新开一个bash 。因此,可以在这里设置单个用户的特殊的环境变量或者特殊的操作,那么每次它新登陆系统或者新开一个bash ,都会去获取相应的特殊的环境变量和特殊操作。

6.4$HOME/.bash_profile

每个用户都可使用该文件输入专用于自己使用的shell 信息。当用户登录时,该文件仅仅执行一次,默认情况下,它设置一些环境变量,执行用户的.bashrc 文件。单个用户此文件的修改只会影响到他以后的每一次登陆系统。因此,可以在这里设置单个用户的特殊的环境变量或者特殊的操作,那么它在每次登陆的时候都会去获取这些新的环境变量或者做某些特殊的操作,但是仅仅在登陆时。
~/.bashrc~/.bash_profile都只对当前的用户永久生效,也就是说假如用户A设置了些类环境变量,这个环境变量只有A才能使用,而对于其他的B,C,D等用户来说,这个变量是不存在的。在根目录下,通过ls -a可以查看这两个文件,正常情况下,这两个文件是隐藏的。

6.5$HOME/.bash_logout

当每次退出系统( 退出bash shell) 时, 执行该文件。

7. ~/.bashrc~/.bash_profile的区别是什么?

答:原则上来说,设置自己的环境变量时,在这两个文件中任意选一个即可,它们的区别在于:~/.bash_profile是交互式login方式进入bash shell运行而~/ .bashrc是交互式non-login方式进入bash shell运行。二者设置大致相同。通俗点说,就是.bash_profile文件只会在用户登录的时候读取一次,而.bashrc在每次打开终端进行一次新的会话时都会读取。

登录 shell 会读取一个或多个启动文件的总结:

文件 内容
/etc/profile 应用于所有用户的全局配置脚本。
$HOME/.bash_profile 用户个人的启动文件。可以用来扩展或重写全局配置脚本中的设置。
$HOME/.bash_login 如果文件 ~/.bash_profile 没有找到,bash 会尝试读取这个脚本。
$HOME/.profile 如果文件 ~/.bash_profile 或文件 ~/.bash_login 都没有找到,bash 会试图读取这个文件。 这是基于 Debian 发行版的默认设置,比方说 Ubuntu。

非登录 shell 会话会读取以下启动文件:

文件 内容
/etc/bash.bashrc 应用于所有用户的全局配置文件。
~/.bashrc 用户个人的启动文件。可以用来扩展或重写全局配置脚本中的设置。

在普通用户看来,文件 ~/.bashrc 可能是最重要的启动文件,因为它几乎总是被读取。非登录 shell 默认 会读取它,并且大多数登录 shell 的启动文件会以能读取 ~/.bashrc 文件的方式来书写。

8. 如何查看某个变量的内容?

答:如果只查看某个变量的内容,用echo,如下所示:
mark

9. 什么是临时有效的环境变量?

答:临时有效的环境变量就是只对当前的shell有效,当我们退出登录或者关闭终端再打开时,这个环境变量就会消失,它是临时的,设置方法是直接使用export命令来添加,如下所示:

biotest@ubuntu:~$ export Words=”Hello, world!”
biotest@ubuntu:~$ echo $Words
Hello, world!
biotest@ubuntu:~

10. 如何查看地自定义的别名?

答:通过set或printenv无法查看通过alias命名的别名,此时需要通过alias来查看,如下所示:

alias egrep=’egrep —color=auto’
alias fgrep=’fgrep —color=auto’
alias grep=’grep —color=auto’
alias l=’ls -CF’
alias la=’ls -A’
alias ll=’ls -alF’
alias ls=’ls —color=auto’

11. Shell中的一些大写字母是什么意思?

答:这些大写字母表示一些特殊的环境变量,如下所示:

变量 内容
DISPLAY 如果你正在运行图形界面环境,那么这个变量就是你显示器的名字。通常,它是 “:0”, 意思是由 X 产生的第一个显示器。
EDITOR 文本编辑器的名字。
SHELL shell 程序的名字。
HOME 用户家目录。
LANG 定义了字符集以及语言编码方式。
OLD_PWD 先前的工作目录。
PAGER 页输出程序的名字。这经常设置为/usr/bin/less。
PATH 由冒号分开的目录列表,当你输入可执行程序名后,会搜索这个目录列表。
PS1 Prompt String 1. 这个定义了你的 shell 提示符的内容。随后我们可以看到,这个变量 内容可以全面地定制。
PWD 当前工作目录。
TERM 终端类型名。类 Unix 的系统支持许多终端协议;这个变量设置你的终端仿真器所用的协议。
TZ 指定你所在的时区。大多数类 Unix 的系统按照协调时间时 (UTC) 来维护计算机内部的时钟 ,然后应用一个由这个变量指定的偏差来显示本地时间。
USER 你的用户名

12. 设置环境变量常用的指令有哪些?

答:常用的命令有echo,export,env,set,unsetreadonly等,如下所示:

(1)echo

查看某个环境变量.

(2)env

查看所有环境变量

(3)set

查看本地定义的所有shell变量.

(4)unset

删除一个环境变量,例如:

biotest@ubuntu:~$ export Words=”Hello, world!”
biotest@ubuntu:~$ echo $Words
Hello, world!
biotest@ubuntu:~$ unset Words
biotest@ubuntu:~$ echo $Words
biotest@ubuntu:~$

(5)readonly

设置只读环境变量.

13. 如何将某程序的目录添加到环境变量?

答:当在shell中输入一个外部命令时,shell就会搜索系统来找到相应的程序,PATH这个环境变量就是定义用于命令和程序查找的目录,通过echo $PATH可以查看环境变量,如下所示:
mark

PATH变量中,可以看到许多由冒号(黄色方框标出的部分)分开的路径。每个冒号就是一个路径,这些搜索路径都是一些可以找到可执行程序的目录列表。当我们输入一个指令时,shell会先检查命令是否是内部命令,不是的话会再检查这个命令是否是一个应用程序。然后shell会试着从这些搜索路径,即PATH(上图中路径)中寻找这些应用程序。如果shell在这些路径目录里没有找到可执行文件。则会报错。若找到,shell内部命令或应用程序将被分解为系统调用并传给Linux内核。在某些时候,我们在Linux中安装了软件,如果没有把软件的可执行文件路径添加到PATH中去的话,要执行某个程序,就需要输入全路径,非常不方便,因此我们需要把软件的安装目录添加到PATH变量中。

PATH环境变量的一个案例

  1. 创建一个可执行文件
    /mnt/hgfs/biotest这个目录下建立一个test.py文件,输入以下内容:
1
2
3
#!/usr/bin/env python3
print("hello, world")

保存,退出。
然后将这个文件权限修改为可执行,如下所示:

1
chmod +x test.py
  1. 测试相对路径与绝对路径调用
    在当前目录下打开客户端,如下所示:

    1
    2
    3
    4
    5
    6
    >biotest@ubuntu:/mnt/hgfs/biotest$ ./test.py # 相对路径调用
    >hello, world
    >biotest@ubuntu:/mnt/hgfs/biotest$
    >biotest@ubuntu:/mnt/hgfs/biotest$ cd
    >biotest@ubuntu:/mnt/hgfs/biotest/test.py # 绝对路径调用
    >hello, world
  2. 未添加到环境变量PATH时的情况
    此时,test.py文件并没添加到PATH的环境变量中,因此直接输入test.py会出错,如下所示:

    1
    2
    >biotest@ubuntu:$ test.py
    >test.py: command not found
  3. 将文件的路径添加到环境变量PATH
    通过设置PATH环境变量,直接用文件名调用:

1
2
3
4
>biotest@ubuntu:$export PATH=$PATH:/mnt/hgfs/biotest
>biotest@ubuntu:$ test.py
>hello, world
>biotest@ubuntu:$

注:在添加路径到环境变量时,用到了export,它的用法是export PATH=$PATH:路径,或export $PATH="路径”

  1. 永久将文件路径添加到环境变量
    此时,将这个客户端关闭,再打开,试着输入test.py,发现出错了,如下所示:
    1
    2
    >biotest@ubuntu:$ test.py
    >test.py: command not found

因为在第4步中,export PATH=$PATH:/mnt/hgfs/biotest只是一种临时添加到环境变量的方法,如果要每次打开客户端时,都能直接执行test.py,则需要将目录添加到.bashrc文件中,步骤如下:
第一,输入biotest@ubuntu:/$ vi ~/.bashrc打开bashrc文件;
第二,移到bashrc文件的最末端,按I,切换到编辑模式,输入export PATH=/mnt/hgfs/biotest:$PATH,再按Esc键,输入wq,回车,退出;
第三,输入source ~/.bashrc,刷新文件,此时,再输入test.py,如下所示:

1
2
>biotest@ubuntu:$ test.py
>hello, world

把客户端关闭或者是重启电脑,再次输入test.py也能够执行,用export查看一下环境变量,如下所示:
mark
可以发现,test.py所在的目录在环境变量中。

如果觉得打开~/.bashrc文件,添加环境变量太麻烦了,可以直接在命令行模式下面进行添加,现在将原来的那个test.py文件拷到另外一个目录(~/Downloads)下面,并把文件名字进行修改,改为test2.py,此时输入以下命令即可:

1
echo 'export PATH=$PATH:~/Downloads'>>~/.bashrc && source ~/.bashrc

运行过程如下所示:

1
2
3
4
5
biotest@ubuntu:~/Downloads$ ./test2.py #相对路径运行
hello, world
biotest@ubuntu:~/Downloads$ echo 'export PATH=$PATH:~/Downloads'>>~/.bashrc && source ~/.bashrc #将路径添加到环境变量,直接运行;;
biotest@ubuntu:~/Downloads$ test2.py
hello, world

通过echo还可以添加alias,如下所示:

1
echo "alias lh='ls -lh'" >> ~/.bashrc && source ~/.bashrc

运行过程如下所示:
mark

什么是非交互式shell?

答:在命令行中输入bash命令,这就是交互式shell,系统执行shell脚本时则是非交互式shell,不同的地方就在于非交互式shell没有命令行提示答。bash shell有一个环境变量即,BASH_ENV环境变量,当shell启动一个非交互式shell进程时,它会检查这个环境变量来查提要执行的启动文件,如果有指定的文件,shell会执行该文件里的命令,这通常包括shell脚本变量设置。这个环境㸄在默认情况下并没有设置,输入printenv BASH_ENV不会返回任何信息。如果BASH_ENV没有设置,shell脚本获取环境变量的过程是这样的:shell脚本是通过启动一个子shell来执行的,子shell可以继承父shell导出过的变量,举例来说,如果父shell是登录shell,在etc/profile/etc/profile.d/*.sh$HOME/.bashrc文件中设置并导出了变量,用于执行脚本的子shell就能够继池在这些变量。需要注意的是,父shell设置但并未导出的变量都是局部变量,子shell无法继承局部变量。

什么是数组变量?

答:环境变量有一个很有用的特性就是它们可以作为数组使用,数组是能够储存多个值的变量,这些值可以单独引用,也可以作为整个数组来引物,要给某个环境变量设置多个值,可以把值放在括号里,值与值之间用空格分隔,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
biotest@ubuntu:~$ mytest=(one two three four five)
biotest@ubuntu:~$ echo $mytest
one
biotest@ubuntu:~$ echo ${mytest[2]}
three
biotest@ubuntu:~$ echo ${mytest[0]}
one
biotest@ubuntu:~$ echo ${mytest[*]}
one two three four five
biotest@ubuntu:~$ unset mytest[2]
biotest@ubuntu:~$ echo ${mytest[*]}
one two four five
biotest@ubuntu:~$ echo ${mytest[3]}
four
biotest@ubuntu:~$ echo ${mytest[*]}
one two four five
biotest@ubuntu:~$ unset mytest
biotest@ubuntu:~$ echo ${mytest[*]}

从上面结果可以知道,数组变量有这样的特点:①如果只输入变量的名称,只返回第1个元素的值;②如果要显其余的变量的值,格式为echo ${mytest[n]},其中n是元素的索引,它是从0开始的,如果要显示全部的内容,需要输入星号(*);③如果要删除数组变量中间的某个元素,删除后,原变量的索引不变;④