9.1 内部变量

内建变量

影响 Bash 脚本行为的变量。

$BASH

Bash程序的路径。

bash$ echo $BASH
/bin/bash

$BASH_ENV

这个环境变量会指向一个 Bash 启动文件,该文件在脚本被调用时会被读取。

$BASH_SUBSHELL

该变量用于提示所处的 subshell 层级。这是在 Bash version 3 中被引入的新特性。

具体用法可以参考 样例21-1

$BASHPID

当前 Bash 进程实例的进程ID号。虽然与 $$ 变量不一样,但是通常它们会给出相同的结果。

bash4$ echo $$
11015


bash4$ echo $BASHPID
11015


bash4$ ps ax | grep bash4
11015 pts/2    R      0:00 bash4

然而...

$BASH_VERSINFO[n]

这是一个6个元素的数组,其中包含了已经安装的 Bash 的版本信息。该变量与变量 $BASH_VERSION 类似,但是更加详细。

$BASH_VERSION

已经安装的 Bash 的版本信息。

利用 $BASH_VERSION 来判断运行的是哪个 shell 是一个不错的方法,因为变量 $SHELL 并不总是能够给出正确的答案。

$CDPATH

变量指定 cd 命令可以搜索的路径,路径之间用冒号进行分隔。该变量的功能类似于指定可执行文件搜索路径的变量 $PATH。可以在本地文件 ~/.bashrc 中设置该变量。

$DIRSTACK

指代目录栈中顶部的值,目录栈由命令 pushdpopd 控制。

该变量相当于命令 dirs,但是 dirs 命令会显示整个目录栈。

$EDITOR

脚本所调用的默认编辑器,通常是 vi 或是 emcas

$EUID

有效用户ID。

有效用户ID(EUID)是指当前用户正在使用的用户ID,可以通过 su 命令修改。

$FUNCNAME

当前运行函数的函数名。

可以参考 样例 A-50

$GLOBIGNORE

文件匹配时所忽略的文件名模式列表。

$GROUPS

当前用户所属的用户组。

该变量存储了当前用户所归属的用户组ID列表,是一个数组。内容与记录在文件 /etc/passwd 和文件 /etc/group 中的一致。

$HOME

当前用户的主目录,其值通常为 /home/username (参考 样例 10-7)。

$HOMENAME

系统启动的初始化脚本通过命令 hostname 给系统分配主机名。而函数 gethostname() 则是给 Bash 的内部变量 $HOSTNAME 赋值。可以参考 样例 10-7

$HOSTTYPE

主机类型。

类似变量 $MACHTYPE,用于识别系统硬件信息。

$IFS

内部字段分隔符。

该变量决定了 Bash 在解析字符串时如何去识别 字段 或单词边界。

$IFS 的缺省值是空白符(空格,制表符以及换行符),但其可以被修改。例如你在处理逗号分隔的文件时可以将其设置为逗号。需要注意 $* 使用保存在 $IFS 中的第一个字符。可以参考 样例 5-1

通过设置 $IFS 来忽略文件路径名中空格带来的影响。

(非常感谢 Stéphane Chazelas 提供了上面的样例并做出的详细说明。)

也可以参考 样例 16-41样例 11-8样例19-14,获取更多使用 $IFS 的技巧。

$IGNOREEOF

忽略 EOF:用于指示 Shell 在注销前需要忽略多少个文件结束符(EOF,contrl-D)。

$LC_COLLATE

经常会在文件 .bashrc 或是文件 /etc/profile 中被设置。该变量控制文件名扩展和模式匹配中的排序顺序。如果设置不得当,LC_COLLATE 将会导致 文件名匹配 中出现非预期结果。

在 Bash 2.05 版本之后,文件名匹配在不再区分中括号中字母的大小写。例如 ls [A-M]* 将会同时匹配 File1.txtfile1.txt 两个文件。如果想要恢复成之前的模式,则需要在文件 /etc/profile 或文件 ~/.bashrc 中通过语句 export LC_COLLATE=C 设置 LC_COLLATE 的值为 C

$LC_CTYPE

这个内部变量控制在 文件匹配 和模式匹配中的字符解析行为。

$LINENO

该变量记录了其在脚本中被使用时所处行的行号。该变量只有在被使用时才有意义,在调试过程中非常有用。

$MACHTYPE

设备类型。

识别系统硬件。

$OLDPWD

上一个工作目录(OLD-Print-Working-Directory),也就是之前所在的目录。

$OSTYPE

操作系统类型。

$PATH

可执行文件搜索路径,其值通常包含 /usr/bin/usr/X11R6/bin//usr/local/bin 等路径。

给定一个命令,shell就会自动从搜索路径包含的目录中利用哈希表搜索该可执行命令。而搜索路径就保存在 环境变量 $PATH 中,其中包含的一系列目录则通过冒号进行分隔。通常情况下,$PATH 会定义在文件 /etc/profile 或文件 ~/.bashrc 中(参考 附录 H)。

PATH=${PATH}:/opt/bin 表示添加目录 /opt/bin 到当前的搜索路径中。在脚本中可以通过这种方式临时添加目录到搜索路径。而当脚本结束时,$PATH 就会恢复到原始值(类似于脚本这样的子进程所作出的修改,不会影响到例如 shell 这样的父进程的环境)。

基于安全考虑,通常在 $PATH 中会省略当前工作目录 ./

$PIPESTATUS

数组 变量保存了最后运行的前台 管道退出状态(es)

$PIPESTATUS 数组中的每一个元素都代表了该管道中相对应命令的退出状态。$PIPESTATUS[0] 表示管道中第一个命令的退出状态,$PIPESTATUS[1] 表示第二个命令的退出状态,以此类推。

在某些场景下,$PIPESTATUS 变量将会产生非预期结果。

Chet Ramey 把上述非预期结果的原因归咎于 ls 命令的行为。如果 ls 将结果输出到没有被读取的管道上,产生的 SIGPIPE 信号将会终止 ls 命令,同时其 退出状态 从期望的 0 变为 141。而同样的情况也会发生在命令 tr 中。

$PIPESTATUS 是一个易失的变量。该变量需要在目标管道执行完成后,且其他任何命令执行之前去捕获。

$PIPESTATUS 不能给出所期望的信息的情况下,使用 pipeline 选项 可能会有帮助。

$PPID

一个进程的 $PPID 即该进程的父进程的进程ID(pid)。

可以与命令 pidof 进行比较。

$PROMPT_COMMAND

该变量存储在主提示符 $PS1 显示之前所需要执行的命令。

$PS1

主提示符,即在命令行中显示的提示符。

$PS2

次要提示符,当需要额外输入时出现的提示符。默认显示为 >

$PS3

三级提示符,显示在 select 循环中(参考 样例 11-30)。

$PS4

四级提示符,当使用 -x [verbose trace] 选项 调用脚本时显示的提示符。默认显示为 +

其可以作为调试的辅助手段,把一些诊断信息显示在 $PS4 中可能会有帮助。

$PWD

工作目录(你当前所在的目录)。

该变量是内建命令 pwd 的翻版。

$REPLY

当没有给 read 命令提供接收参数时的默认接收参数。该变量同样适用于 select 菜单接收用户输入值的场景,需要注意的是,用户只需要输入菜单项的编号,而不需要输入完整的菜单项内容。

$SECONDS

该变量记录到目前为止脚本执行的时间,单位为秒。

$SHELLOPTS

该只读变量记录了 shell 中已启用的 选项 列表。

$SHLVL

当前 shell 的层级,即嵌套了多少层 Bash 。如果命令行的层级 $SHLVL 为 1,那么在其中执行的脚本层级则增加到 2。

该变量 不受 subshell 影响。当你需要指出嵌套了多少层 subshell 时,需要使用变量 $BASH_SUBSHELL

$TMOUT

如果 $TMOUT 被设为非 0 值 time,那么 shell 会在 $time 秒后超时,然后导致 shell 登出。

在 Bash 2.05b 版本之后,可以在脚本中将 read 命令与 $TMOUT 变量进行结合。

在脚本中,同样也存在其他一些实现超时功能的更复杂的方法。其中一个方法是设置一个循环的计时器,当脚本超时的时候,计时器会给脚本发送一个信号。同时,也需要一个处理信号的程序来 捕获(参考 样例 32-5)由循环计时器产生的中断。

样例 9-2. 限时输入

还有一种方法是使用 stty

样例 9-3. 再来一次,限时输入

可能最简单的方法就是利用 read 命令的 -t 选项。

样例 9-4. 限时 read

$UID

用户 ID。

记录在文件 /etc/passwd 中当前用户的用户标识号。

该 ID 表示的是当前用户的真实 ID,即使用户通过 su 命令临时切换至另一个用户,这个 ID 也不会改变。$UID 是一个只读变量,不能够被命令行或是脚本中的命令所修改,并与内建命令 id 相对应。

样例 9-5. 我是 root 用户吗?

还可以参考 样例2-3

变量 $ENV$LOGNAME$MAIL$TERM$USER 以及 $USERNAME 并不是 Bash 的 内建变量,而是在 Bash 或系统的某个启动文件中,被设置而成的 环境变量。代表当前用户登录 shell 名称的变量 $SHELL 是在文件 /etc/password 或是某个初始化脚本中被设定的,它也不是一个 Bash 的内建变量。

位置参数

$0, $1, $2 等

位置参数。出现在从命令行传递给脚本、函数或是通过内建命令 set 设置变量时(参考 样例 4-5 或是 样例 15-16)。

$#

命令行参数或是位置参数的个数(参考 样例 36-2)。

$*

将所有的位置参数整合,视作一个单词。

该参数必须是被引用的状态,"$*"

$@

该参数等同于 $*,但其中每个参数都是独立的被引用的字符串。也就是说,所有的参数都是被原封不动的进行传递,并没有被解析或是扩展。这意味着,参数列表中的每一个参数都被独立视为一个单词。

同样,该参数必须是被引用的状态,"$@"

样例 9-6. 参数列表:利用 $* 和 $@ 列出参数

shift 命令执行后,$@ 将会保留除了 $1 之外的剩余的命令行参数,而 $1 则会被丢弃。

参数 $@ 也可被用作过滤 shell 脚本输入的工具。结构 cat "$@" 可以接受来自标准输入 stdin 的输入,也可以接受传递给脚本的参数中的文件中的输入。参考 样例 16-24样例 16-25

样例 9-7. $* 和 $@ 的不一致行为

$@$* 仅在被双引号引用时才会表现出不同。

样例 9-8. 当 $IFS 为空时 $* 和 $@ 的表现

其他特殊参数

$-

使用 set 命令设置的脚本标记。参考 样例 15-16

$!

运行在后台的最后一个任务的 进程ID

$! 用于控制任务:

也可以这么使用:

$_

该变量被设置为上一个执行的命令的最后一个参数。

样例 9-9. 下划线变量

$?

命令、函数 或是脚本自身的 退出状态。参考 样例 24-7

$$

脚本自身的进程 ID。该变量 $$ 通常在脚本构建独有的临时文件时被使用(参考 样例 32-6样例 16-31,以及 样例 15-27)。该方法通常比调用 mktemp 命令更简单。

注记

栈寄存器是一段连续的内存空间,在该空间中,存入(压栈)的值是以倒序的方式取出(出栈)的。最后一个存入的值被最先取出。其通常又被称为后进先出(LIFO)或是下堆栈。

当前运行脚本的进程 ID 就是 $$

类似于 递归。在本文中,嵌套是指代一种模式被嵌入在一种更大的模式中。在 1913 年出版的韦伯斯特大辞典中用一种更加优雅的方式解释了什么是嵌套:“一组按体积大小排列的盒子、箱子或是类似的东西,它们中的每一个都被放入到另一个更大的箱子中。(A collection of boxes, cases, or the like, of graduated size, each put within the one next larger.)”。

术语“变量(argument)”和“参数(parameter)”通常情况下是可以互相交换使用的。在本书中,它们具有相同的含义:传入脚本或函数的变量。

在 subshell 中运行的脚本,$$ 返回脚本的进程 ID 而非 subshell 的。

  1. Footnotes placeholder

  2. Footnotes placeholder

最后更新于

这有帮助吗?