1. 变量分类
shell 变量分为两种,系统变量,用户自定义变量
系统变量:$PATH
,$HOME
,$PWD
,$SHELL
,$USER
。
2. 变量定义和定义规则
2.1. 变量定义方法
定义变量
变量名=值
撤销变量unset 变量名
定义静态变量readonly 变量名
2.2. 变量定义规则
- 与其他编程语言一样,变量的定义不能使用数字开头。
- 在赋值表达式,等号的两边不能存在空格,这和其他编程语言规范是不同的。
- 脚本的变量变量命名一般所有字母全部大写。
2.3. 变量值的获取
$变量名称
这样就可以将变量的值读取出来,如果没有$
符号那么echo
会将变量名称当作字符串输出
2.4. 变量赋值
变量名称=数值值
或变量名称=字符串
2.5. shell命令返回值用于变量赋值
变量名称=
命令
或变量名称=$(命令)
例如path=$(ls -l "/c/Users/lyj/Desktop/my items/shell")
3. 环境变量
bash shell用一个叫作环境变量(environment variable)的特性来存储有关shell会话和工作环
境的信息(这也是它们被称作环境变量的原因)。这项特性允许你在内存中存储数据,以便程序
或shell中运行的脚本能够轻松访问到它们。这也是存储持久数据的一种简便方法。
3.1. 局部变量
查看局部变量命令
set
set
命令会显示为某个特定进程设置的所有环境变量,包括局部变量、全局变量
以及用户定义变量。
$ set
BASH=/bin/bash
[...]
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
BASH_CMDS=()
BASH_LINENO=()
BASH_SOURCE=()
[...]
注意:局部环境变量只能在定义它们的进程中可见,即局部变量则只对创建它们的
shell可见。
3.2. 全局变量
查看局部变量命令
env
或printenv
$ printenv HOME
/home/Christine
$
$ env HOME
env: HOME: No such file or directory
$
注意:全局环境变量对于shell会话和所有生成的子shell都是可见的。
4. 设置与删除环境变量
在bash shell中,环境变量分为两类:
- 全局变量
- 局部变量
4.1. 设置局部变量
一旦启动了bash shell(或者执行一个shell脚本),就能创建在这个shell进程内可见的局部变量了。可以通过等号给环境变量赋值,值可以是数值或字符串。例如下面这样:
$ echo $my_variable
$ my_variable=Hello
$
$ echo $my_variable
Hello
设置了局部环境变量后,就能在shell进程的任何地方使用它了。但是,如果生成了另外一个 shell,它在子shell中就不可用。通过命令所返回的空行就能够证明这一点。当你退出子shell并回到原来的shell时,这个局部环境变量依然可用。
类似地,如果你在子进程中设置了一个局部变量,那么一旦你退出了子进程,那个局部环境
变量就不可用。
4.2. 设置全局环境变量
在设定全局环境变量的进程所创建的子进程中,该变量都是可见的。创建全局环境变量的方法是先创建一个局部环境变量,然后再把它导出到全局环境中。
$ my_variable="I am Global now"
$
$ export my_variable
$
$ echo $my_variable
I am Global now
在定义并导出局部环境变量 my_variable 后, bash 命令启动了一个子shell。在这个子shell中能够正确的显示出变量 my_variable 的值。该变量能够保留住它的值是因为
export
命令使其变成了全局环境变量。
有一点需要注意,即使修改子shell中的全局环境变量但是并不会影响到父shell中该变量的值。
4.3. 删除环境变量
可以创建新的环境变量,自然也能删除已经存在的环境变量。可以用
unset
命令完成这个操作。在unset
命令中引用环境变量时,记住不要使用$
。
$ echo $my_variable
I am Global now
$
$ unset my_variable
$
$ echo $my_variable
$
4.4 默认的 shell 环境变量
默认情况下,bash shell会用一些特定的环境变量来定义系统环境。这些变量在你的Linux系统上都已经设置好了,可以放心使用。当然不同的Linux发行版本默认的环境变量是不同的。
bash shell支持的Bourne变量:(这只是其中一部分)
表6-1 bash shell支持的Bourne变量
变 量 描 述
CDPATH
冒号分隔的目录列表,作为 cd 命令的搜索路径
HOME
当前用户的主目录
IFS
shell用来将文本字符串分割成字段的一系列字符
MAIL
当前用户收件箱的文件名(bash shell会检查这个文件,看看有没有新邮件)
MAILPATH
冒号分隔的当前用户收件箱的文件名列表(bash shell会检查列表中的每个文件,看看有没有新邮件)
OPTARG
getopts 命令处理的最后一个选项参数值
OPTIND
getopts 命令处理的最后一个选项参数的索引号
PATH
shell查找命令的目录列表,由冒号分隔
PS1
shell命令行界面的主提示符
PS2
shell命令行界面的次提示符
bash shell环境变量:(这只是其中一部分)
表6-2 bash shell环境变量
变 量 描 述
BASH
当前shell实例的全路径名
BASH_ALIASES
含有当前已设置别名的关联数组
BASH_ARGC
含有传入子函数或shell脚本的参数总数的数组变量
BASH_ARCV
含有传入子函数或shell脚本的参数的数组变量
BASH_CMDS
关联数组,包含shell执行过的命令的所在位置
BASH_COMMAND
shell正在执行的命令或马上就执行的命令
BASH_ENV
设置了的话,每个bash脚本会在运行前先尝试运行该变量定义的启动文件
BASH_EXECUTION_STRING
使用 bash -c 选项传递过来的命令
BASH_LINENO
含有当前执行的shell函数的源代码行号的数组变量
BASH_REMATCH
只读数组,在使用正则表达式的比较运算符=~进行肯定匹配(positive match)时,
包含了匹配到的模式和子模式
BASH_SOURCE
含有当前正在执行的shell函数所在源文件名的数组变量
BASH_SUBSHELL
当前子shell环境的嵌套级别(初始值是0)
BASH_VERSINFO
含有当前运行的bash shell的主版本号和次版本号的数组变量
BASH_VERSION
当前运行的bash shell的版本号
BASH_XTRACEFD
若设置成了有效的文件描述符( 0 、 1 、 2 ),则 'set -x' 调试选项生成的跟踪输出
可被重定向。通常用来将跟踪输出到一个文件中
BASHOPTS
当前启用的bash shell选项的列表
BASHPID
当前bash进程的PID
COLUMNS
当前bash shell实例所用终端的宽度
COMP_CWORD
COMP_WORDS 变量的索引值,后者含有当前光标的位置
COMP_LINE
当前命令行
COMP_POINT
当前光标位置相对于当前命令起始的索引
COMP_KEY
用来调用shell函数补全功能的最后一个键
COMP_TYPE
一个整数值,表示所尝试的补全类型,用以完成shell函数补全
COMP_WORDBREAKS
Readline库中用于单词补全的词分隔字符
COMP_WORDS
含有当前命令行所有单词的数组变量
COMPREPLY
COPROC
含有由shell函数生成的可能填充代码的数组变量
占用未命名的协进程的I/O文件描述符的数组变量
DIRSTACK
含有目录栈当前内容的数组变量
EMACS
设置为 't' 时,表明emacs shell缓冲区正在工作,而行编辑功能被禁止
ENV
如果设置了该环境变量,在bash shell脚本运行之前会先执行已定义的启动文件(仅
用于当bash shell以POSIX模式被调用时)
EUID
当前用户的有效用户ID(数字形式)
FCEDIT
供 fc 命令使用的默认编辑器
FIGNORE
在进行文件名补全时可以忽略后缀名列表,由冒号分隔
FUNCNAME
当前执行的shell函数的名称
注意:不是所有的默认环境变量都会在运行
set
命令时列出。虽然这些都是默认环境变量,但并不是每一个环境变量都存在有一个值。
5. 设置修改 PATH 环境变量
当你在shell命令行界面中输入一个外部命令时shell 必须搜索系统来找到对应的程序。 PATH 环境变量定义了用于进行命令和程序查找的目录。注意不同的Linux 发行版本所输出的信息是不相同的。如果命令或者程序的位置没有包括在 PATH 变量中,那么如果不使用绝对路径的话,shell是无法找到的。如果shell找不到指定的命令或程序,它会产生一个错误信息:kaili linux 默认的PATH 环境变量的内容是这样的:
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:
/sbin:/bin:/usr/games:/usr/local/games
$
上方输出中显示了有8个可供shell用来查找命令和程序。 PATH 中的目录使用冒号分隔。
很多时候应用程序放置可执行文件的目录常常不在 PATH 环境变量所包含的目录中。解决的办法是保证 PATH 环境变量包含了所有存放应用程序的目录。可以把新的搜索目录添加到现有的 PATH 环境变量中。
那怎么将新安装的软件的可执行文件的目录添加到PATH变量中呢? 把新的搜索目录添加到现有的 PATH 环境变量中,无需从头定义。 PATH 中各个目录之间是用冒号分隔的。只需引用原来的 PATH 值,然后再给这个字符串添加新目录就行了。例如下面这样:
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:
/sbin:/bin:/usr/games:/usr/local/games
$
$ PATH=$PATH:/home/christine/Scripts # 引用原有的PATH值,添加目录
$
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/
games:/usr/local/games:/home/christine/Scripts
注意:如果希望子shell也能找到你的程序的位置,一定要记得把修改后的 PATH 环境变量通过 export
命令导出。
6. 定位系统环境变量
登入Linux系统启动一个bash shell时,默认情况下bash会在几个文件中查找命令。这些文件叫作启动文件或环境文件。bash检查的启动文件取决于你启动bash shell的方式。
启动bashshell有3种方式:
- 登录时作为默认登录shell
- 作为非登录shell的交互式shell
- 作为运行脚本的非交互shell
6.1 登录shell
当你登录Linux系统时,bash shell会作为登录shell启动。登录shell会从5个不同的启动文件里
读取命令:
- /etc/profile
- $HOME/.bash_profile
- $HOME/.bashrc
- $HOME/.bash_login
- $HOME/.profile
/etc/profile文件是系统上默认的bash shell的主启动文件。系统上的每个用户登录时都会执行
这个启动文件。另外4个启动文件是针对用户的,可根据个人需求定制。
6.2 交互式shell
如果你的bash shell不是登录系统时启动的(比如是在命令行提示符下敲入 bash 时启动),那么你启动的shell叫作交互式shell。交互式shell不会像登录shell一样运行,但它依然提供了命令行提示符来输入命令。如果bash是作为交互式shell启动的,它就不会访问/etc/profile文件,只会检查用户HOME目录中的.bashrc文件。
6.3 非交互shell
最后一种shell是非交互式shell。系统执行shell脚本时用的就是这种shell。不同的地方在于它没有命令行提示符。
6.4 环境变量持久化
对全局环境变量来说(Linux系统中所有用户都需要使用的变量),可能更倾向于将新的或修
改过的变量设置放在/etc/profile文件中,但这可不是什么好主意。如果你升级了所用的发行版,
这个文件也会跟着更新,那你所有定制过的变量设置可就都没有了。
最好是在/etc/profile.d目录中创建一个以.sh结尾的文件。把所有新的或修改过的全局环境变
量设置放在这个文件中。
在大多数发行版中,存储个人用户永久性bash shell变量的地方是$HOME/.bashrc文件。这一
点适用于所有类型的shell进程。但如果设置了 BASH_ENV 变量,那么记住,除非它指向的是
$HOME/.bashrc,否则你应该将非交互式shell的用户变量放在别的地方。
6.5 数组变量
环境变量有一个很酷的特性就是,它们可作为数组使用。数组是能够存储多个值的变量。这
些值可以单独引用,也可以作为整个数组来引用。
要给某个环境变量设置多个值,可以把值放在括号里,值与值之间用空格分隔。
$ mytest=(one two three four five)
$
没什么特别的地方。如果你想把数组像普通的环境变量那样显示,将无法获取所有的数组元素。
$ echo $mytest
one
$
要引用一个单独的数组元素,就必须用代表它在数组中位置的数值索引值。索引值要用方括号括起来。
$ echo ${mytest[2]}
three
$
要显示整个数组变量,可用星号作为通配符放在索引值的位置。
$ echo ${mytest[*]}
one two three four five
$
也可以改变某个索引值位置的值。
$ mytest[2]=seven
$
$ echo ${mytest[*]}
one two seven four five
$
甚至能用 unset 命令删除数组中的某个值,但是要小心,这可能会有点复杂。看下面的例子。
$ unset mytest[2]
$
$ echo ${mytest[*]}
one two four five
$
$ echo ${mytest[2]}
$
$ echo ${mytest[3]}
four
可以在 unset 命令后跟上数组名来删除整个数组。
$ unset mytest
$
$ echo ${mytest[*]}
$