陈颂光
全栈工程师,承接从编译器到网站的各类软件开发与咨询,也可以聊历史哲学。
关注我的 GitHub

BASH概览

BASH(GNU Bourne-Again SHell)是一个与 sh 兼容的命令解释程序,可以执行从标准输入或者文件中读取的命令。 Bash 也整合了 Korn 和 C Shell (ksh 和 csh) 中的优秀特性。现在很多GNU/Linux都用Bash作为默认的shell,因而在系统管理方面bash脚本仍很常用。

运行BASH程序##

在主流GNU/Linux发行版中,很可能已经预装好BASH。

REPL

在命令行界面,则没有前台工件在进行时就很可能处于Bash,如正在用其它shell则运行bash。正在图形界面中则可通过打开终端窗口或按Ctrl-Alt-F2(F2可换成F2到F6任一,换成F7则回到图形界面)交互式地使用shell。

Bash用READLINE库读入行,因而有强大的行编辑、历史扩展和自动补全功能,详情见文档。其中,如果不人为设置,应可用以下常用的类emacs快捷键:

移动快捷键 用途
C-a或HOME 移动到当前行的开始。
C-e或END 移动到当前行的结尾。
C-f或向右 向前移动一字。
C-b或向左 向后移动一字。
M-f或C-向右 向前移动到下一词尾。词由字符 (字母和数字) 组成。
M-b或C-向左 向后移动到当前或上一词首。
C-l 清除屏幕,保留当前行在屏幕顶端。有参数时,刷新当前行,不清屏。
操纵历史行快捷键 用途
C-p或向上 从历史列表中取得前一个命令,从列表中向后移动。
C-n或向下 从历史列表中取得后一个命令,从列表中向前移动。
M-< 移动到历史中的第一行。
M-> 移动到输入历史行的末尾,也就是当前输入的行的末尾。
C-r 从当前行开始向后搜索,按照需要在历史中向“上”移动。这是一个增量的搜索。
C-s 从当前行开始向前搜索,按照需要在历史中向“下”移动。这是一个增量的搜索。
M-p 从当前行开始向后,使用非增量搜索来查找用户给出的字符串。
M-n 从当前行开始向前,使用非增量搜索来查找用户给出的字符串。
M-C-y 将前一个命令的第一个参数 (通常是上一行的第二个词) 插入到 point 位置。有参数n时,将前一个命令的第n个词(前一个命令中的词从0开始计数)插入到point位置。负数参数则插入前一个命令倒数第 n 个词。
M-., M-_ 插入前一个命令的最后一个参数(上一历史条目的最后一个词)。有参数时,行为类似于yank-nth-arg。后继的调用将从历史列表中向后移动,依次将每行的最后一个参数插入。
M-C-e 扩展行,像 shell 做的那样。其中包含别名和历史扩展,还有所有的 shell 词的扩展。
M-^ 在当前行进行历史扩展。
C-o 接受当前行,加以执行,从历史中取出相对当前行的下一行进行编辑。 任何参数都被忽略。
C-xC-e 启动一个编辑器,编辑当前命令行,将结果作为 shell 命令运行。 Bash 将依次试着运行 $FCEDIT, $EDITOR, 和 emacs 作为编辑器。
改变文本快捷键 用途
C-d或DELETE 删除 point 处的字符。如果 point 在行首,行中没有字符,最后一次输入的字符 没有被关联到 delete-char,将返回 EOF.
C-q, C-v 将输入的下一字符保持原样添加到行中。例如,可以用它来插入类似 C-q 的字符。
C-v TAB 插入一个跳格符号。
C-t 将 point 之前的字符向前移动,越过 point 处的字符,同时也改变 point 的位置。 如果 point 在行尾,将调换 point 之前的两个字符。负数参数没有作用。
M-t 将 point 之前的词向前移动,越过 point 处的词,同时也改变 point 的位置。 如果 point 在行尾,将调换行中的最后两个词。
M-u 将当前 (或下一个) 词变成全大写。有负值的参数时,将前一个词变为大写, 但是不移动 point。
M-l 将当前 (或下一个) 词变成全小写。有负值的参数时,将前一个词变为小写, 但是不移动 point。
M-c 将当前 (或下一个) 词变为首字大写。有负值的参数时,将前一个词变为首字大写, 但是不移动 point。
剪切和粘贴快捷键 用途
C-k 剪切从 point 到行尾的文本。
C-u 反向剪切到行首
M-d 剪切从 point 到当前词尾,或者如果 point 在词之间,那么剪切到下一词尾。
C-w 剪切 point 之后的词,使用空白作为词的边界。剪切的文本被保存于 kill-ring 中。
M-|删除 point 两边的所有空格和跳格。  
C-y 将 kill-ring 顶部的内容粘贴到 point 处的缓冲区中
M-y 轮转 kill-ring,粘贴新的顶部内容。只能在 yank 或 yank-pop 之后使用。
补全快捷键 用途
TAB 试着对 point 之前的文本进行补全。 Bash 依次试着将文本作为一个变量 (如果文本以 $ 开始),一个用户名 (如果文本以 ~ 开始),主机名 (如果文本以 @ 开始),或者命令(以及别名和函数) 来补全。如果这些都没有匹配,将尝试文件名补全。
M-?) 列出 point 之前的文本可能的补全。
M-* 插入已产生的 point 之前的文本所有的补全。
M-/ 尝试对 point 之前的文本进行文件名补全。
C-x / 列出 point 之前的文本可能的补全,将它视为文件名。
M-~ 尝试对 point 之前的文本进行补全,将它视为用户名。
C-x ~ 列出 point 之前的文本可能的补全,将它视为用户名。
M-$ 尝试对 point 之前的文本进行补全,将它视为 shell 变量。
C-x $ 列出 point 之前的文本可能的补全,将它视为 shell 变量。
M-@ 尝试对 point 之前的文本进行补全,将它视为主机名。
C-x @ 列出 point 之前的文本可能的补全,将它视为主机名。
M-! 尝试对 point 之前的文本进行补全,将它视为命令名。命令补全尝试着将此文本 依次与别名,保留字,shell 函数,shell 内建命令,最后是可执行文件名进行匹配。
C-x ! 列出 point 之前的文本可能的补全,将它视为命令名。
M-TAB 尝试对 point 之前的文本进行补全,将此文本与历史列表中的行相比较来查找可能的补全匹配。
M-{ 进行文件名补全,将可能的补全列表放在花括号中插入,使得列表可以被 shell 使用。

bash支持命令相关的可编程自动补全,因此可相当准确,这些脚本通常放在/usr/share/bash-completion/completions/。

键盘宏快捷键 用途
C-x ( 开始保存输入字符为当前键盘宏。
C-x ) 停止保存输入字符为当前键盘宏,保存宏定义。
C-x e 重新执行上次定义的键盘宏,即显示出宏中的字符,好像它们是从键盘输入的一样。
其它快捷键 用途
C-x C-r 读入 inputrc 文件的内容,合并其中的按键关联和变量赋值。
C-g 取消当前编辑命令,鸣终端响铃 (按照 bell-style 的设置来做)。
M-a, M-b, M-x, … 如果有 Meta 前缀的字符 x 是小写的,那么与命令相关连的是对应的大写字符。
ESC 将输入的下一个字符加上 Meta 前缀。 ESC f 等价于 Meta-f.
C-_, C-x C-u 增量的撤销,分别记住每一行。
M-r 撤销这一行的所有修改。这与执行命令 undo 足够多次的效果相同,将这一行恢复到初始状态。
M-& 对当前词进行波浪线扩展。
C-@, M- 在 point 处设置 mark。如果给出了数值的参数,标记被设置到那个位置。
C-x C-x 交换 point 和 mark。当前光标位置被设置为保存的位置,旧光标位置被保存为 mark。
C-] 读入一个字符,point 移动到这个字符下一次出现的地方。负数将搜索上一个出现。
M-C-] 读入一个字符,point 移动到这个字符上一次出现的地方。负数将搜索下面的出现。
M-# 没有数值的参数时,readline变量comment-begin 的值将被插入到当前行首。如果给出一个数值的参数,命令的行为类似于一个开关: 如果行首字符不匹配 comment-begin的值,将插入这个值,否则 匹配 comment-begin 的字符将被从行首删除。在两种情况下,这一行都被接受, 好像输入了新行符一样。comment-begin 的默认值使得这个命令将当前行变成 一条shell 注释。如果数值参数使得注释字符被删除,这一行将被 shell 执行。
M-g point 之前的词被当作路径扩展的一个模式,尾部暗含了一个星号。这个模式被用来 为可能的补全产生匹配的文件名列表。
C-x * point 之前的词被当作路径扩展的一个模式,匹配的文件名的列表被插入,替换这个词。 如果给出一个数值参数,在路径扩展之前将添加一个星号。
C-x g 显示 glob-expand-word 可能产生的扩展的列表,重绘当前行。如果给出一个数值参数,在路径扩展之前将添加一个星号。
C-x C-v 显示当前 bash 实例的版本信息。

历史扩展

可方便地通过历史扩展调用历史命令:

命令 用途
!n 引用命令行 n
!-n 引用当前命令行减去 n
!! 引用上一条命令相当于!-1
!string 引用最近的以 string 开始的命令
!?string[?] 引用最近的包含 string 的命令。尾部的 ? 可以被忽略,如果 string 之后紧接着一个新行符。
^string1^string2^ 快速修正。重复上一条命令,只将 string1 替换为 string2。
!# 到此为止输入的整个命令行。

再加上分号和词指示器可以从命令中选择期望的词。如果词指示器以 ^, $, *, -, 或 % 开始,可以忽略分号。词被从行首开始编号,第一个词被表示为0。插入当前行中的词以单个空格分隔。

|词指示器|选取| |:—|:—| |0|第 0 个词,也就是命令名| |n|第 n 个词| |^|第一个参数。也就是,第 1 个词。| |$|最后的参数。| |%|最近一次搜索 ?string?' 匹配的词。| |x-y|一组词;-y’ 是 0-y' 的简写。| |*|除了第0个的词。这是 1-$’ 的同义词。| |x|x-$ 的简写| |x-|-$ 的简写,就像 x,但是忽略最后一个词。|

再后面,可以出现一个或多个下述修饰符序列,每一个都有前缀分号:

修饰符 用途
h 删除文件名组成的尾部,只保留头部。
t 删除文件名组成中前面的成分,保留尾部。
r 删除 .xxx 形式中尾部的后缀成分,保留基本名称部分。
e 删除所有内容,保留尾部的后缀。
p 打印新的命令,但是不执行它。
q 引用替换所得的词,使它不再进行替换。
x 引用替换所得的词,类似与 q, 但是会根据 blanks,空白和换行符分解为词。
s/old/new/ 将事件行中出现的第一个old替换为new。任何分隔符都可以用来代替/,最后一个分隔符是可选的,如果它是行的最后一个字符。old和new中的分隔符和&(在new中引用old)可以用一个反斜杠来转义。
& 重复上一次替换。
g 使得改变被整个事件行所接受。用于与:s或:&结合成:gs或:g&。

运行文件

如果命令存至一文件中,可以用以下命令运行它们并提供参数(BASH选项见文档):

bash options ... fileName arg  ...

退出状态是脚本中执行的最后一个命令的退出状态(没执行命令则为0)。

脚本

脚本(假设bash路径为/bin/bash)应以

#!/bin/bash

开始,且文件应设为可执行。

词法

分词##

BASH把输入分解为称为词的结构单元,其中分隔符(元字符)有 、&、;、(、)、<、>、空格、制表符,空白(即空格、制表符)随后被忽略,分为:
形式
名字(标识符) 只由字母,数字和下划线构成的词,并且以字符或下划线起始
控制操作符 如下之一: || & && ; ;; ( ) |

如果不被引用, 并且不是一个简单命令的起始词,也不是case或for命令的第三个词,下列词被识别为保留字: ! case do done elif else esac fi for function if in select then until while { } time [[ ]]

以#起始的词使得这个词和所有同一行上所有剩余的字符都作为注释被忽略。

引用用来去掉特定字符或词的特殊意义。引用可以用来禁止对特殊字符的处理,阻止保留字被识别,还用来阻止参数的扩展。 上面在 DEFINITIONS 定义 中列出的每个元字符 metacharacters 对于 shell 都有特殊意义。如果要表达它的本义,必须引用它。 有三种引用机制:转义字符、单引号和双引号。

一个未被引用的反斜杠 () 是转义字符它保留其后下一个字符的字面意义,除非那是一个换行符。如果 \ 和换行符成对出现,并且反斜杠自身没有被引用,那么 <newline>被视为续行标志 (意思是,它被从输入流中删除并忽略了)。

将字符放在单引号之中,将保留引用中所有字符的字面意义。单引号不能包含在单引号引用之中,即使前面加上了反斜杠。

将字符放在双引号中,同样保留所有字符的字面意义,例外的情况是 $ , ` ,和 \ 。 字符 $和 `在双引号中仍然具有特殊意义。反斜杠只有后面是下列字符时才有特殊意义: $ , ` ,”, \ ,或 . 双引号可以包含在双引号引用中,但要在前面加上一个反斜杠。 特殊的参数 *和 @在双引号中有特殊意义。

形式为 $’string’ 的词会被特殊处理。它被扩展为 string,其中的反斜杠转义字符被替换为 ANSI C 标准中规定的字符。反斜杠转义序列,如果存在的话,将做如下转换:

转义序列 转换为
\a 响铃
\b 回退
\e 字符 Esc
\f 进纸
\n 新行符
\r 回车
\t 水平跳格
\v 竖直跳格
\| 反斜杠  
\’ 单引号
\nnn 一个八比特字符,它的值是八进制值 nnn (一到三个数字)。
\xHH 一个八比特字符,它的值是十六进制值 HH (一到两个十六进制数字)。
\cx 一个 ctrl-x 字符

扩展结果是单引号引用的,就好像 $ 符号不存在一样。

双引号引用字符串前面加上一个 $ 符号将使得这个字符串被根据当前语言环境来转换。如果当前语言环境是 C 或者 POSIX,这个符号将被忽略。如果这个字符串被翻译并替换了,那么替换结果是双引号引用的。

扩展

命令行的扩展是在拆分成词之后进行的。 扩展的顺序是:花括号展开, 波浪线扩展, 参数扩展和算术扩展还有命令替换(按照从左到右的顺序), 词的拆分, 最后是路径名扩展.

还有一种附加的扩展:进程替换只有在支持它的系统中有效。

只有 花括号展开, 词的拆分, 和 路径名扩展在扩展前后的词数会发生改变;其他扩展总是将一个词扩展为一个词。唯一的例外是上面提到的”$@” 和 “${name[@]}” 。

花括号展开###

花括号展开是一种可能产生任意字符串的机制。这种机制类似于路径名扩展, 但是并不需要存在相应的文件。 花括号扩展的模式是一个可选的前导字符,后面跟着一系列逗号分隔的字符串,包含在一对花括号中,再后面是一个可选的附言。 前导被添加到花括号中的每个字符串前面,附言被附加到每个结果字符串之后,从左到右进行扩展。

花括号扩展可以嵌套。扩展字符串的结果没有排序;而是保留了从左到右的顺序。例如, a{d,c,b}e 扩展为 ade ace abe。

花括号扩展是在任何其他扩展之前进行的,任何对其他扩展有特殊意义的字符都保留在结果中。它是严格字面上的。 Bash不会对扩展的上下文或花括号中的文本做任何语义上的解释。

正确的花括号扩展必须包含没有引用的左括号和右括号,以及至少一个没有引用的逗号。任何不正确的表达式都不会被改变。可以用反斜杠来引用{ 或 , 来阻止将它们识别为花括号表达式的一部分。为了避免与参数扩展冲突,字符串 ${ 不被认为有效的组合。

这种结构通常用来简写字符串的公共前缀远比上例中为长的情况,例如:mkdir /usr/local/src/bash/{old,new,dist,bugs}或者chown root /usr/{ucb/{ex,edit},lib/{ex?.?*,how_ex}}

波浪线扩展

如果一个词以没有引用的波浪线字符 (~') 开始,所有在第一个没有引用的斜线 (/’) 之前的字符 (或者是这个词的所有字符,如果没有没引用的斜线的话) 都被认为是 tilde-prefix(波浪线前缀)。如果 tilde-prefix 中没有被引用的字符,那么波浪线之后的字符被认为是 login name(登录名)。如果登录名是空字符串,波浪线将被替换为 shell 参数 HOME的值。如果没有定义 HOME,将替换为执行此 shell 的用户的个人目录。否则,tilde-prefix 被替换为与指定登录名相联系的个人目录。

如果 tilde-prefix 是 ~+',将使用 shell 变量 PWD的值来替换。如果 tilde-prefix 是 ~-‘,并且设置了 shell 变量 OLDPWD ,将使用这个变量值来替换。如果在 tilde-prefix 中,波浪线之后的字符串由一个数字 N 组成,前缀可选的 +' 或者 -‘,那么 tilde-prefix将被替换为目录栈中相应的元素,就是将 tilde-prefix 作为参数执行内建命令 dirs显示的结果。如果 tilde-prefix 中波浪线之后的字符是一个数字,没有前缀,那么就假定有一个 `+’。

如果登录名不合法,或者波浪线扩展失败,这个词将不会变化。

在变量赋值中,对于 :或 =之后的字符串会立即检查未引用的 tilde-prefix。这种情况下,仍然会进行波浪线扩展。因此,可以使用带波浪线的文件名来为 PATH , MAILPATH ,和 CDPATH赋值,shell 将赋予扩展之后的值。

参数扩展

字符 $ 引入了参数扩展,命令替换和算术扩展。要扩展的参数名或符号可能包含在花括号中,花括号可选的,但是可以使得要扩展的变量不会与紧随其后的字符合并,成为新的名称。

使用花括号的时候,匹配的右括号是第一个 },并且它没有被反斜杠引用或包含在一个引用的字符串中,也没有包含在一个嵌入的算术扩展,命令替换或是参数扩展中。

形式 意义
${parameter} 被替换为 parameter 的值。如果 parameter是一个位置参数,并且数字多于一位时;或者当紧随 parameter之后有不属于名称一部分的字符时,都必须加上花括号。
${parameter:-word} 使用默认值。如果 parameter未定义或值为空,将替换为 word的扩展。否则,将替换为 parameter的值。
${parameter:=word} 赋默认值。如果 parameter未定义或值为空, word的扩展将赋予 parameter . parameter的值将被替换。位置参数和特殊参数不能用这种方式赋值。
${parameter:?word} 如果 parameter未定义或值为空,word (或一条信息,如果 word不存在) 的扩展将写入到标准错误;shell 如果不是交互的,则将退出。否则,parameter 的值将被替换。
${parameter:+word} 使用可选值。如果 parameter未定义或非空,不会进行替换;否则将替换为 word扩展后的值。
${parameter:offset}  
${parameter:offset:length} 子字符串扩展。扩展为parameter 的最多 length 个字符,从 offset指定的字符开始。如果忽略了 length,扩展为 parameter 的子字符串,从 offset 指定的字符串开始。length 和 offset 是算术表达式。length 必须是一个大于等于 0 的数值。如果 offset 求值结果小于 0,值将当作从 parameter 的值的末尾算起的偏移量。如果 parameter是 @,结果是 length 个位置参数,从 offset 开始。如果 parameter 是一个数组名,以 @ 或 * 索引,结果是数组的length 个成员,从 ${parameter[offset]} 开始。子字符串的下标是从 0 开始的,除非使用位置参数时,下标从 1 开始。
${!prefix*} 扩展为名称以 prefix 开始的变量名,以特殊变量 IFS的第一个字符分隔。
${#parameter} 替换为 parameter 的值的长度 (字符数目)。如果 parameter是 * 或者是 @ ,替换的值是位置参数的个数。如果 parameter是一个数组名,下标是 *或者是 @ ,替换的值是数组中元素的个数。
${parameter#word}  
${parameter##word} word被扩展为一个模式,就像路径扩展中一样。如果这个模式匹配 parameter的值的起始,那么扩展的结果是将 parameter扩展后的值中,最短的匹配 (# 的情况) 或者最长的匹配(##的情况) 删除的结果。如果 parameter是 @或者是 * ,则模式删除操作将依次施用于每个位置参数,最后扩展为结果的列表。如果 parameter是一个数组变量,下标是 @或者是 * ,模式删除将依次施用于数组中的每个成员,最后扩展为结果的列表。
${parameter%word}  
${parameter%%word} word 被扩展为一个模式,就像路径扩展中一样。如果这个模式匹配 parameter 扩展后的值的尾部,那么扩展的结果是将 parameter扩展后的值中,最短的匹配 (% 的情况) 或者最长的匹配(%%的情况) 删除的结果。如果 parameter是 @或者是 * ,则模式删除操作将依次施用于每个位置参数,最后扩展为结果的列表。如果 parameter是一个数组变量,下标是 @或者是 * ,模式删除将依次施用于数组中的每个成员,最后扩展为结果的列表。
${parameter/pattern/string}  
${parameter//pattern/string} pattern 被扩展为一个模式,就像路径扩展中一样。parameter被扩展,其值中最长的匹配 pattern 的内容被替换为 string。在第一种形式中,只有第一个匹配被替换。第二种形式使得 pattern中所有匹配都被替换为 string。如果 pattern 以 # 开始,它必须匹配 parameter 扩展后值的首部。如果 pattern 以 % 开始,它必须匹配 parameter扩展后值的尾部。如果 string 是空值,pattern 的匹配都将被删除,pattern 之后的 / 将被忽略。如果 parameter是 @或者是 * ,则替换操作将依次施用于每个位置参数,最后扩展为结果的列表。如果 parameter是一个数组变量,下标是 @或者是 * ,模式删除将依次施用于数组中的每个成员,最后扩展为结果的列表。

如果 parameter 的第一个字符是一个感叹号,将引进一层间接变量。bash 使用以 parameter 的其余部分为名的变量的值作为变量的名称;接下来新的变量被扩展,它的值用在随后的替换当中,而不是使用parameter 自身的值。这也称为间接扩展.例外情况是 ${!prefix*}。

其中,每种情况中,word 都要经过波浪线扩展,参数扩展,命令替换和算术扩展。如果不进行子字符串扩展,bash 测试一个没有定义或值为空的参数;忽略冒号的结果是只测试未定义的参数。

命令替换

命令替换允许以命令的输出替换命令名。有两种形式:

$(command)

还有

`command`

进行扩展的步骤是执行 command,以它的标准输出替换它,并且将所有后续的换行符删除。内嵌的换行符不会删除,但是它们可能会在词的拆分中被删除。命令替换 $(cat file) 可以用等价但是更快的方法$(< file) 代替。

当使用旧式的反引号替换形式时,反斜杠只有其字面意义,除非后面是 $ , ` ,或者是 \ . 第一个前面没有反斜杠的反引号将结束命令替换。当使用 $(command)形式时,括号中所有字符组成了整个命令;没有被特殊处理的字符。

命令替换可以嵌套。要在使用反引号形式时嵌套,可以用反斜杠来转义内层的反引号。

如果替换发生在双引号之中,结果将不进行词的拆分和路径扩展。

算术扩展

算术扩展允许算术表达式的求值和结果的替换。算术扩展的格式是:

$((expression))

表达式 expression被视为如同在双引号之中一样,但是括号中的双引号不会被特殊处理。表达式中所有词都经过了参数扩展,字符串扩展,命令替换和引用的删除。算术替换可以嵌套。

如果表达式 expression非法, bash输出错误提示消息,不会进行替换。

求值使用固定宽度的整数,不检查是否溢出,但是被零除会被捕获,标记为错误。 操作数及其优先级和聚合程度与 C 语言中相同。下列操作数的列表按照相同优先级的操作数其级别来分组。列出的级别顺序是优先级递减的。

运算 意义
id++ id– 变量自增/自减 (在后)
++id –id 变量自增/自减 (在前)
- + (单目的) 取负/取正
! ~ 逻辑和位取反
** 乘幂
* / % 乘,除,取余
+ - 加,减
« » 左/右位移
<= >= < > 比较
== != 相等/不等
& 位与 (AND)
^ 位异或 (exclusive OR)
| 位或 (OR)
&& 逻辑与 (AND)
|| 逻辑或 (OR)
expr?expr:expr 条件求值
= *= /= %= += -= <<= >>= &= ^= |= 赋值
expr1 , expr2 逗号表达式

shell 变量可以作为操作数;在表达式求值之前会进行参数扩展。在表达式中,可以用名称引用 shell 变量,不必使用参数扩展的语法。变量被引用时,其值被作为算术表达式来求值。shell 变量用于表达式中时,不必启用整数属性。以 0 为前导的常量被当作八进制数,以 0x 或 0X 作为前导表明是十六进制。其他情况下,数字的形式是 [base# ]n,这里 base 是一个 2 到 64的十进制数值,作为数字的基数,n 是在这个基数中数字的值。如果忽略了 base# ,将以 10 为基数。大于 10 的数字依次以小写字母,大写字母,@ 和 _ 表示。如果 base 小于或等于 36,在表示 10 与 35 之间的数字时小写字母和大写字母可以互换。操作符根据优先级顺序进行求值。圆括号中的子表达式被最先求值,可能会超越上面的优先级规则。

进程替换

Process substitution (进程替换) 只有在支持命名管道 (FIFOs),或者支持使用 /dev/fd 方式为打开的文件命名的系统中才可用。它的形式是<(list')或者是>(list')。进程 list 运行时的输入或输出被连接到一个 FIFO 或者 /dev/fd中的文件。文件的名称作为一个参数被传递到当前命令,作为扩展的结果。如果使用 >(list’) 形式,向文件写入相当于为 list提供输入。如果使用 <(list’) 形式,可以读作为参数传递的文件来获得 list的输出。如果可能的话,进程替换是与参数和变量扩展,命令替换和算术扩展同时发生的。

词的拆分

shell 检测不在双引号引用中发生的参数扩展,命令替换和算术扩展的结果,进行词的拆分。

shell 将 IFS的每个字符都作为定界符,根据这些字符来将其他扩展的结果分成词。如果 IFS没有定义,或者它的值是默认的 ,那么 IFS字符的任何序列都将作为分界之用。如果 IFS的值是默认之外的值,那么词开头和结尾的空白字符 space 和 tab都将被忽略,只要空白字符在 IFS的值之内 (即, IFS包含空白字符)。任何在 IFS之中但是不是 IFS空白的字符,以及任何相邻的 IFS空白字符,将字段分隔开来。 IFS空白字符的序列也被作为分界符。如果 IFS的值是空,不会发生词的拆分。

显式给出的空值参数(’‘、”“)将被保留。隐含的空值参数,来自于空值的参数扩展,如果没有引用则将被删除。如果空值的参数在双引号引用中扩展,结果是空值的参数,将被保留。注意如果没有发生扩展,不会进行词的拆分。

路径名扩展

词的拆分之后,除非设置过 -f选项, bash搜索每个词,寻找字符 * , ? ,和 [ . 如果找到了其中之一,那么这个词被当作一个模式, 被替换为匹配这个模式的文件名以字母顺序排列的列表。如果没有找到匹配的文件名,并且 shell 禁用了 nullglob选项,这个词将不发生变化。如果设置了 nullglob选项并且没有找到匹配,这个词将被删除。如果启用了 nocaseglob选项,匹配时将不考虑字母的大小写。当模式用作路径名扩展时,字符.如果在一个名称的开始或者紧随一个斜杠之后,那么它必须被显式地匹配,除非设置了 dotglob shell 选项。当匹配一个路径名时,斜杠符必须被显式地匹配。其他情况下,字符.不会被特殊对待。

环境变量 GLOBIGNORE可以用来限制匹配 pattern 的文件名集合。如果设置了 GLOBIGNORE,每个匹配的文件名如果匹配 GLOBIGNORE中任何一个模式的话将从匹配的列表中删除。文件名.和..总是被忽略,即使设置了 GLOBIGNORE。但是,设置 GLOBIGNORE和启用 shell 选项 dotglob效果是相同的,因此所有其他以 .开头的文件名将被匹配。要得到原来的行为 (忽略所有以.开头的文件名),可以将.*添加为 GLOBIGNORE 的模式之一。选项 dotglob被禁用,如果 GLOBIGNORE没有定义时。

任何模式中出现的字符,除了下面描述的特殊模式字符外,都匹配它本身。模式中不能出现 NUL 字符。如果要匹配字面上的特殊模式字符,它必须被引用。

特殊模式 意义
* 匹配任何字符串包含空串。
? 匹配任何单个字符。
[…] 匹配所包含的任何字符之一。用一个连字符-分隔的一对字符意思是一个范围表达式,任何排在它们之间的字符,包含它们,都被匹配。排序使用当前语言环境的字符顺序和字符集。如果 [之后的第一个字符是一个 !或是一个 ^那么任何不包含在内的字符将被匹配。范围表达式中字符的顺序是由当前语言环境和环境变量 LC_COLLATE 的值 (如果设置了的话) 决定的。一个 - 只有作为集合中第一个或最后一个字符时才能被匹配。一个 ]只有是集合中第一个字符时才能被匹配。在 [ 和 ]中,character classes (字符类) 可以用 [:class:]这样的语法来指定,这里 class 是在 POSIX.2 标准中定义的下列类名之一: alnum alpha ascii blank cntrl digit graph lower print punct space upper word xdigit,一个字符类匹配任何属于这一类的字符。word 字符类匹配字母,数字和字符 _。在 [和 ]中,可以用 [=c=] 这样的语法来指定等价类,它匹配与字符 c 有相同归并权值的字符。在 [和 ]中,语法 [.symbol.] 匹配归并符号symbol。

如果使用内建命令 shopt 启用了 shell 选项 extglob,将识别另外几种模式匹配操作符。下面的描述中,pattern-list 是一个 或多个模式以 | 分隔的列表。复合的模式可以使用一个或多个下列的子模式构造出来:

模式 意义
?(‘pattern-list’) 匹配所给模式零次或一次出现
*(‘pattern-list’) 匹配所给模式零次或多次出现
+(‘pattern-list’) 匹配所给模式一次或多次出现
@(‘pattern-list’) 准确匹配所给模式之一
!(‘pattern-list’) 任何除了匹配所给模式之一的字串

引用消除

经过前面的扩展之后,所有未引用的字符 \ , ‘ ,以及并非上述扩展结果的字符 “ 都被删除。

语法

简单命令

(可选的)一系列变量赋值, 紧接着是空格白分隔的词和重定向, 然后以一个控制操作符结束. 第一个词指明了要执行的命令, 它被作为第 0 个参数. 其余词被作为这个命令的参数. 简单命令的返回值是它的退出状态, 或是 128+n’, 如果命令被信号n结束的话.

参数

一个参数是一个储存值的实体。它可以是一个名称、一个数字或者是下述特殊字符之一。从 shell 的角度来看,一个变量 是一个由名称代表的参数。一个变量有一个值以及零个或多个属性。属性可以使用内建命令 declare来设置。 如果给一个参数赋值,那么它就被定义了。空字符串是有效的值。一旦一个变量被定义了,它只能用内建命令 unset来取消

一个变量可以用这样的语句形式来赋值:

name=[value]

如果没有给出值 value,变量就被赋为空字符串。所有值 values都经过了波浪线扩展,参数和变量扩展,命令替换,算术扩展和引用的删除。如果变量设置了整数属性,那么值 value将进行算术扩展,即使没有应用 $((…)) 扩展。 不会进行词的拆分,除非是特殊参数”$@”。不会进行路径的扩展。 赋值语句也出现在下列内建命令中,作为它们的参数: declare , typeset , export , readonly ,和 local。

位置参数是以一或多个数字代表的参数,除了 0。位置参数是在 shell 启动时,根据它的参数来赋值的,也可以用内建命令 set 来重新赋值。位置参数不能用赋值语句来赋值。在一个 shell 函数被执行的时候,位置参数会被暂时地替换掉。 当位置参数由两个以上的数字构成时,它必须放在括号内。

shell 对一些参数做特殊处理,这些参数只能被引用而不能被赋值。

参数 意义
* 扩展为位置参数,从 1 开始。如果扩展发生在双引号中,它扩展为一个词,值是各个参数,以特殊变量 IFS的第一个字符分隔。也就是说,”$*” 等价于”$1c$2c…“,这里 c是变量 IFS的第一个字符。如果没有设置 IFS,那么参数将用空格分隔。
@ 扩展为位置参数,从 1 开始。如果扩展发生在双引号中,每个参数都将扩展为一个词。也就是说,”$@” 等价于”$1” “$2” …如果位置参数不存在,”$@” 和 $@扩展为空 (即,它们被删除了)。
# 扩展为位置参数的个数,以十进制表示。
? 扩展为最近执行的前台管道的状态。
- 扩展为当前选项标志。标志是在启动时或以内建命令 set指定的,或者是 shell 自身设置的 (例如选项 -i)。
$ 扩展为 shell 的进程 ID。在一个 () 子 shell 中,它扩展为当前 shell 的进程 ID 而不是子 shell 的。
! 扩展为最近一次执行的后台 (异步) 命令的进程号。
0 扩展为 shell 或者 shell 脚本的名称。这个变量是在 shell 初始化时设置的。如果 bash是执行脚本文件时启动的, $0将设置为那个文件的名称。如果 bash启动时的参数包含 -c,那么 $0被设置为启动命令行被执行后的第一个参数,如果有的话。否则,它被设置为用来启动 bash 的文件名,就是参数 0。
_ shell 启动时,设置为 shell 或参数中被执行的 shell 脚本的绝对路径名。然后,在扩展时扩展为上一个命令的最后一个参数。它也被设置为被执行的每个命令的文件全名并且被设置到这个命令执行的环境当中。当检查邮件时,这个参数保存着正在检查的邮件文件的名称。

另外还有一些对bash有特殊含义的变量如PATH,详情见手册。

数组

提供了一维数组变量。任何变量都可以作为一个数组。数组的大小没有上限,也没有限制在连续对成员引用和赋值时有什么要求。数组以整数为下标,从 0 开始。

如果变量赋值时使用语法 name[subscript]=value,那么就会自动创建数组。 subscript被当作一个算术表达式,结果必须是大于等于 0 的值。要显式地定义一个数组,使用 declare -a namedeclare -a name[subscript],这时 subscript 被忽略。数组变量的属性可以用内建命令 declare和 readonly来指定。每个属性对于所有数组元素都有效。

数组赋值可以使用复合赋值的方式,形式是name=(value1 ... valuen),这里每个value 的形式都是 [subscript]=string。string必须出现。如果出现了可选的括号和下标,将为这个下标赋值,否则被赋值的元素的下标是语句中上一次赋值的下标加一。下标从 0 开始。这个语法也被内建命令 declare所接受。单独的数组元素可以用上面介绍的语法name[subscript]=value 来赋值。

数组的任何元素都可以用 ${name[subscript]} 来引用。花括号是必须的,以避免和路径扩展冲突。如果subscript 是@或,它扩展为 name 的所有成员。这两种下标只有在双引号中才不同。在双引号中,${name[]} 扩展为一个词,由所有数组成员的值组成,用特殊变量 IFS的第一个字符分隔;${name[@]} 将 name 的每个成员扩展为一个词。如果数组没有成员,${name[@]} 扩展为空串。这种不同类似于特殊参数*和@的扩展。${# name[subscript]} 扩展为${name[subscript]} 的长度。如果 subscript 是 * 或者是 @,扩展结果是数组中元素的个数。引用没有下标数组变量等价于引用元素 0。

内建命令 unset用于销毁数组。unset name[subscript]将销毁下标是 subscript 的元素。unset name, 这里 name 是一个数组,或者unset name[subscript], 这里subscript 是 * 或者是 @,将销毁整个数组。

内建命令 declare , local ,和 readonly都能接受 -a选项,从而指定一个数组。内建命令 read可以接受 -a选项,从标准输入读入一列词来为数组赋值。内建命令 set和 declare使用一种可以重用为输入的格式来显示数组元素。

重定向

在命令执行前,它的输入和输出可能被重定向,使用一种 shell 可以解释的特殊记法。重定向也可以用于为当前 shell执行环境 打开和关闭文件。下列重定向操作符可以前置或者放在简单命令之中的任何位置,或者放在 command之后。重定向是以出现的顺序进行处理的,从左到右。

下列描述中,如果文件描述符被忽略,并且第一个重定向操作符是 < ,那么重定向指的是标准输入 (文件描述符是 0)。如果重定向操作符的第一个字符是 > ,那么重定向指的是标准输出 (文件描述符是 1)。

下列描述中,重定向操作符之后的词如果没有特殊说明,都要经过brace expansion, tilde expansion, parameter expansion, command substitution, arithmetic expansion, quote removal, pathname expansion, 还有 word splitting。如果扩展为多于一个词, bash将报错。

注意重定向的顺序非常重要。例如,命令ls > dirlist 2>&1将标准输出和标准错误重定向到文件 dirlist ,而命令ls 2>&1 > dirlist只会将标准输出重定向到文件 dirlist ,因为在标准输出被重定向到文件 dirlist 中之前,标准错误被复制为标准输出。

一些文件名在重定向中被 bash 特殊处理,如下表所示:

文件名 意义
/dev/fd/fd 如果 后一fd 是一个合法的整数,文件描述符 fd 将被复制。
/dev/stdin 文件描述符 0 被复制。
/dev/stdout 文件描述符 1 被复制。
/dev/stderr 文件描述符 2 被复制。
/dev/tcp/host/port 如果 host 是一个合法的主机名或 Internet 地址,并且 port 是一个整数端口号或服务名,bash 试图建立与相应的 socket (套接字) 的TCP 连接。
/dev/udp/host/port 如果 host 是一个合法的主机名或 Internet 地址,并且 port 是一个整数端口号或服务名,bash 试图建立与相应的 socket (套接字) 的UDP 连接。

打开或创建文件错误将导致重定向出错。

形式 含义
[n]<word 重定向输入使得以 word扩展结果为名的文件被打开并通过文件描述符 n读取,如果没有指定 n那么就作为标准输入 (文件描述符为 0) 读取。
[n]>word 重定向输出使得以 word扩展结果为名的文件被打开并通过文件描述符 n写入,如果没有指定 n那么就作为标准输出 (文件描述符为 1) 写入。如果启用了内建命令 set的 noclobber选项,那么如果 word 扩展后得到的文件名存在并且是一个普通的文件,重定向将失败。
[n]»word 这种方式的输出重定向使得以 word扩展结果为名的文件被打开并通过文件描述符 n 从尾部添加。如果没有指定 n就使用标准输出 (文件描述符 1)。如果文件不存在,它将被创建。
&>word 相当于>word 2>&1
>&word 允许使用这种结构将标准输出和标准错误 (文件描述符 1 和 2) 重定向到以 word扩展结果为名的文件中。
«[-]word here-document delimiter 这种重定向使得 shell 从当前源文件读取输入,直到遇到仅包含 word的一行 (并且没有尾部空白) 为止。直到这一点的所有行被用作命令的标准输入。不会对 word进行 parameter expansion, command substitution, arithmetic expansion,或者 pathname expansion。如果 word中任何字符是引用的, delimiter将是对 word进行引用删除的结果,here-document 中的行不会被扩展。如果 word 没有被引用,here-documnet 中的所有行都要经过parameter expansion, command substitution, 和 arithmetic expansion。在后一种情况下,字符序列 <newline>被忽略;必须用 \引用字符 \ , $ ,和 ` .如果重定向操作符是 «- ,那么所有前导的 tab 字符都被从输入行和包含 delimiter的行中删除。这样使得 shell 脚本中的 here-document 可以被更好地缩进。
«<word word 被扩展,提供给命令作为标准输入。
[n]<&word 用于复制文件描述符。如果 word扩展为一个或多个数字, n代表的文件描述符将成为那个文件描述符的复制。如果 word中的数字并未指定一个被用于读取的文件描述符,将产生一个重定向错误。如果 word扩展为 - ,文件描述符 n将被关闭。如果没有指定 n,将使用标准输入 (文件描述符 0)。
[n]>&word 用于复制输出文件描述符。如果没有指定 n,将使用标准输出 (文件描述符 1)。如果 word中的数字并未指定一个被用于输出的文件描述符,将产生一个重定向错误。特殊情况下,如果忽略了 n,并且 word 并非扩展为一个或多个数字,标准输出和标准错误将被重定向,和前面描述的一样。
[n]<&digit- 将文件描述符 digit 移动为文件描述符 n ,或标准输入 (文件描述符 0),如果没有指定 n 的话。digit 复制为 n 之后就被关闭了。
[n]>&digit- 将文件描述符 digit 移动为文件描述符 n ,或标准输出 (文件描述符 1),如果没有指定 n 的话。
[n]<>word 使得以 word扩展结果为名的文件被打开,通过文件描述符 n 进行读写。如果没有指定 n那么就使用文件描述符 0。如果文件不存在,它将被创建。

管道

一个或多个命令的序列,用字符 | 分隔。管道的格式是这样:

[time [-p]] [ ! ] command [ | command2 ... ]

命令 command的标准输出通过管道连接到命令 command2的标准输入。连接是在命令指定的任何重定向之前进行的。 管道中的每个命令都作为单独的进程来执行(即,在一个子 shell 中启动)。

如果保留字 ! 作为管道前缀,管道的退出状态将是最后一个命令的退出状态的逻辑非值。否则,管道的退出状态就是最后一个命令的。 shell 在返回退出状态值之前,等待管道中的所有命令返回。

如果保留字 time作为管道前缀,管道中止后将给出执行管道耗费的用户和系统时间。选项 -p 将使输出符合 POSIX 指定的格式。 环境变量 TIMEFORMAT可以设置为一个指定时间信息应当如何显示的格式字符串。

序列

一个或多个管道,用操作符 ; 、 & 、 && 或 ||分隔的序列, 并且可以选择用 ; 、& 或换行符结束. 这些序列操作符中, &&和 ||优先级相同,其次是 ;和 &,它们的优先级是相同的。

如果一个命令是由控制操作符 & 结束的, shell 将在后台的子 shell 中执行这个命令。shell 不会等待命令执行结束,返回状态总是 0。 以分号 ;分隔的命令会被顺序执行;shell 会等待每个命令依次结束。返回状态是最后执行的命令的返回状态。

AND command1 && command2 中command2只有在 command1返回 0 时才被执行。 OR 序列command1 || command2 中command2只有在 command1返回非 0 状态时才被执行。 AND 和 OR 序列的返回状态是序列中最后执行的命令的返回状态。

复合命令

compound command(复合命令) 是如下情况之一:

命令形式 特点
(list) list 序列将在一个子 shell 中执行。变量赋值和影响 shell 环境变量的内建命令在命令结束后不会再起作用。返回值是序列的返回值。
{ list; } list 序列将在当前 shell 环境中执行。序列必须以一个新行符或分号结束。返回值是序列的返回值。注意与元字符 ( 和 ) 不同,{ 和 } 是保留字,必须出现在能够识别保留字的场合。由于它们不会产生断词,它们和序列之间必须用空格分开。
((expression)) 表达式 expression 将被算术求值。如果表达式的值非零,返回值就是 0;否则返回值是 1。
[[ expression ]] 返回 0 或 1,取决于条件表达式 expression 求值的情况。[[ 和 ]] 中的词不会进行词的拆分和路径的扩展处理而tilde 扩展,参数和变量扩展,算术扩展,命令替换,函数替换和引用的去除则都将进行。 当使用 == 和 != 操作符时,操作符右边的字符串被认为是一个模式,模式匹配规则进行匹配。如果匹配则返回值是 0,否则返回 1。模式的任何部分可以被引用,强制使它作为一个字符串而被匹配。
for name [ in word ] ; do list ; done in 之后的一系列词会被扩展,产生一个项目列表。变量 name 被依次赋以这个列表中的每个元素,序列 list 每次都被执行。如果 in word 被忽略,那么 for 命令遍历已设置的位置参数。返回值是最后一个命令的返回值。如果 in 之后的词扩展的结果是空列表,就不会执行任何命令,返回值是 0。
for (( expr1 ; expr2 ; expr3 )) ; do list ; done 首先,算术表达式 expr1 被求值。然后算术表达式 expr2 被循环求值,直到它等于 0。每次 expr2 结果非零时,序列 list 都被执行,算术表达式 expr3 被求值。如果任何表达式被忽略,将被视为执行结果是 1。返回值是序列 list 中被执行的最后一个命令的返回值;或者是 false,如果任何表达式非法的话。
select name [ in word ] ; do list ; done in 之后的一系列词会被扩展,产生一个项目列表。这个扩展后的词集合被输出到标准错误上,每个前面加上一个数字。如果 in word 被忽略,将输出位置参数 。 PS3提示符将被显示出来,等待从标准输入得到一行输入。如果输入是一个数字且显示中有对应的词,那么变量 name的值将设置为这个词。如果输入一个空行,那么词和提示符将再次显示出来。如果读入了一个 EOF,命令就结束。任何其他值将设置变量 name为空。读入的行保存为变量 REPLY .序列 list在每次选择之后都会执行,直到执行了一个 break命令。 select的退出状态是序列 list中执行的最后一个命令的退出状态,如果没有执行命令就是 0。
case word in [ [(] pattern [ | pattern ] ... ) list ;; ] ... esac 首先扩展 word, 然后依次试着用每个 pattern 来匹配它,使用与路径扩展相同的匹配规则。如果找到一个匹配,相应的序列将被执行。找到一个匹配之后,不会再尝试其后的匹配。如果没有模式可以匹配,返回值是 0。否则,返回序列中最后执行的命令的返回值。
if list; then list; [ elif list; then list; ] ... [ else list; ] fi 序列 if list被执行。如果退出状态是 0,then list 将被执行。否则,各个 elif将被分别执行,如果退出状态是 0,相应的 then list 将被执行,命令结束。否则,else list 将被执行,如果存在的话。退出状态是最后执行的命令的退出状态,或者是 0,如果所有条件都不满足。
while list; do list; done 不断地执行序列 do list,直到list中最后一个命令返回 0。退出状态是序列 do list 中最后一个命令的退出状态,或者是 0,如果没有执行任何命令。
until list; do list; done 序列 do list执行直到list中最后一个命令返回非零状态值。退出状态是序列 do list 中最后一个命令的退出状态,或者是 0,如果没有执行任何命令。
[ function ] name () { list; } 这样可以定义一个名为 name 的函数。函数体 body 是包含在 { 和 } 之间的命令序列 list。在指定将 name 作为一个命令运行的场合,这个序列将被执行。函数的退出状态是函数体最后执行的命令的退出状态。

其中表达式可以用下列操作符结合起来。根据优先级的降序列出如下:

表达式 意义
( expression ) 返回表达式 expression 的值。括号可以用来提升操作符的优先级。
! expression 返回真,如果表达式 expression返回假。
expression1 && expression2 返回真,如果表达式 expression1和 expression2都返回真(短路)。
expression1 || expression2 返回真,如果表达式 expression1或者 expression2二者之一返回真(短路)。

条件表达式用来测试文件属性,进行字符串和算术比较。表达式使用下面的单目或二进制操作构造。如果某操作的任何 file 参数的形式是 /dev/fd/n,那么将检查文件描述符 n。如果某操作的 file 参数是 /dev/stdin,/dev/stdout 或者 /dev/stderr 之一,将分别检查文件描述符 0,1 和 2。

表达式 意义
-a file 如果 file 存在则为真。
-b file 如果 file 存在且为块设备则为真。
-c file 如果 file 存在且为字符设备则为真。
-d file 如果 file 存在且是一个目录则为真。
-e file 如果 file 存在则为真。
-f file 如果 file 存在且为普通文件则为真。
-g file 如果 file 存在且是设置组ID的 (sgid) 则为真。
-h file 如果 file 存在且为符号链接则为真。
-k file 如果 file 存在且设置了sticky 位 (粘滞位) 则为真。
-p file 如果 file 存在且是一个命名管道 (FIFO) 则为真。
-r file 如果 file 存在且可读则为真。
-s file 如果 file 存在且大小大于零则为真。
-t fd 如果文件描述符 fd是打开的且对应一个终端则为真。
-u file 如果 file 存在且是设置用户ID的 (suid) 则为真。
-w file 如果 file 存在且可写则为真。
-x file 如果 file 存在且可执行则为真。
-O file 如果 file 存在且为有效用户ID所拥有则为真。
-G file 如果 file 存在且为有效组ID所拥有则为真。
-L file 如果 file 存在且为符号链接则为真。
-S file 如果 file 存在且为套接字则为真。
-N file 如果 file 存在且上次读取后被修改过则为真。
file1 -nt file2 如果 file1 比 file2 要新 (根据修改日期),或者如果 file1 存在而 file2 不存在,则为真。
file1 -ot file2 如果 file1 比 file2 更旧,或者如果 file1 不存在而 file2 存在,则为真。
file1 -ef file2 如果 file1 和 file2 指的是相同的设备和 inode 号则为真。
-o optname 如果启用了 shell 选项 optname则为真。
-z string 如果 string 的长度为 0 则为真。
-n string 如果 string 的长度非 0 则为真。
string1 == string2 如果字符串相等则为真。= 可以用于使用 == 的场合来兼容 POSIX 规范。
string1 != string2 如果字符串不相等则为真。
string1 < string2 如果 string1 在当前语言环境的字典顺序中排在 string2 之前则为真。
string1 > string2 如果 string1 在当前语言环境的字典顺序中排在 string2 之后则为真。
arg1 OP arg2 OP是 -eq , -ne , -lt , -le , -gt ,或 -ge之一。这些算术二进制操作返回真,如果 arg1 与 arg2 分别是相等,不等,小于,小于或等于,大于,大于或等于关系。 arg1和 arg2可以是正/负整数。

执行过程

简单命令扩展##

当执行一个简单命令时,shell 进行下列扩展,赋值和重定向,从左到右。

  1. 解释器标记为与变量赋值 (在命令名之前的) 和重定向有关的词被保存等待随后处理。
  2. 并非变量赋值或重定向的词被扩展。如果扩展后仍然有词保留下来,第一个词被作为命令名,其余词是参数。
  3. 重定向按照上面讲到的规则进行。
  4. 每个变量赋值中 = 之后的文本在赋予变量之前要经过波浪线扩展、参数扩展、命令替换、算术扩展和引用删除。 如果没有得到命令名,变量赋值影响当前 shell 环境。否则,变量被加入被执行的命令的环境中,不影响当前 shell 环境。如果任何赋值动作试图为只读变量赋值,将导致出错,命令以非零状态值退出。 如果没有得到命令名,重定向仍会进行,但是不影响当前 shell 环境。重定向出错将使命令以非零状态值退出。 如果扩展后有命令名保留下来,那么执行过程如下所示。否则,命令退出。 如果在任何扩展中包含命令替换,那么整个命令的退出状态是最后一个命令替换的退出状态。如果没有进行命令替换,命令以状态零退出。

命令执行##

命令被拆分为词之后,如果结果是一个简单命令和可选的参数列表,将执行下面的操作。 如果命令名中没有斜杠,shell 试图定位命令位置。如果存在同名的 shell函数,函数将被执行,像上面 FUNCTIONS 中讲到的一样。如果名称不是一个函数,shell 从 内建命令中搜索它。如果找到对应命令,它将被执行。 如果名称既不是 shell 函数也不是一个内建命令,并且没有包含斜杠, bash搜索 PATH的每个成员,查找含有此文件名 (可执行文件) 的目录。 Bash使用散列表来储存可执行文件的全路径。只有在散列表中没有找到此命令,才对 PATH进行完整的搜索。如果搜索不成功,shell 输出错误消息,返回退出状态 127。 如果搜索成功,或者命令中包含一个或多个斜杠,shell 在单独的执行环境中执行这个程序。参数 0 被设置为所给名称;命令的其他参数被设置为所给的参数,如果有的话。 如果执行失败,因为文件不是可执行格式,并且此文件不是目录,就假定它是一个 shell script (脚本),一个包含 shell 命令的文件。此时将孵化出一个子 shell 来执行它。子 shell 重新初始化自身,效果就好像是执行了一个新的 shell 来处理脚本一样,但是父 shell 保存的命令位置仍然被保留。 如果程序是以 #!开头的文件,那么第一行的其余部分指定了这个程序的解释器。shell 执行指定的解释器,如果操作系统不会自行处理这种可执行文件格式的话。解释器的参数由下面三部分组成:程序第一行中解释器名称之后的可选的一个参数,程序的名称,命令行参数,如果有的话。

函数##

一个 shell 函数,保存着一系列的命令,等待稍后执行。当 shell 函数名作为一个简单命令名使用时,这个函数名关联的命令的序列被执行。函数在当前 shell 的上下文环境中执行;不会创建新的进程来解释它们 (这与 shell 脚本的执行形成了对比)。当执行函数时,函数的参数成为执行过程中的位置参数。特殊参数 # 被更新以反映这个变化。位置参数 0 不会改变。函数执行时, FUNCNAME变量被设置为函数的名称。函数和它的调用者在 shell 执行环境的所有其他方面都是一样的,特殊情况是 DEBUG陷阱不会被继承,除非函数设置了trace 属性。函数中的局部变量可以使用内建命令 local来声明。通常情况下,变量和它们的值在函数和它的调用者之间是共享的。如果函数中执行了内建命令 return,那么函数结束,执行从函数调用之后的下一个命令开始。函数结束后,位置参数的值以及特殊参数 # 都将重置为它们在函数执行前的值。函数名和定义可以使用内建命令 declare或 typeset加上 -f参数来列出。如果在 declare或 typeset命令中使用 -F选项将只列出函数名。函数可以使用内建命令 export加上 -f参数导出,使得子 shell 中它们被自动定义。函数可以是递归的。对于递归调用的次数没有硬性限制。

别名##

别名机制允许将一个词来替换为一个字符串,如果它是一个简单命令的第一个词的话。shell 记录着一个别名列表,可以使用内建命令 alias和 unalias来定义和取消。每个命令的第一个词,如果没有引用,都将被检查是否是一个别名。 如果是,这个词将被它所指代的文本替换。别名和替换的文本可以包含任何有效的 shell 输入,包含上面列出的元字符,特殊情况是别名中不能包含 =。替换文本的第一个词也被检查是否 是别名,但是如果它与被替换的别名相同,就不会再替换第二次。这意味着可以用 ls作为 “ls -F”的别名, bash不会递归地展开替换文本。如果别名的最后一个字符是 blank ,那么命令中别名之后的下一个词也将被检查是否能进行别名展开。 别名可以使用 alias命令来创建或列举出来,使用 unalias命令来删除。在替换文本中没有参数机制。如果需要参数,应当使用 shell 函数段落)。 如果 shell 不是交互的,别名将不会展开,除非使用内建命令 shopt设置了 expand_aliases选项。 关于别名的定义和使用中的规则比较混乱。 Bash在执行一行中的任何命令之前,总是读入至少完整一行的输入。别名在命令被读取时展开,而不是在执行的时候。因此,别名定义如果和另一个命令在同一行,那么不会起作用,除非读入了下一行。 别名定义之后,同一行中的命令不会受新的别名影响。这种行为在函数执行时存在争议,因为别名替换是在函数定义被读取时发生的,而不是函数被执行的时候,因为函数定义本身是一个复合命令。结果,在函数中定义的别名只有当这个函数执行完才会生效。为了保险起见,应当总是将别名定义放在单独的一行,不在复合命令中使用 alias。不管什么情况下,别名都被 shell 函数盖过。

命令执行环境##

shell 有执行环境的概念,由下列内容组成:

  • shell 启动时继承的打开的文件,例如在内建命令 exec 中使用重定向修改的结果
  • 当前工作目录,使用 cd,pushd 或者 popd 设置,或是由shell 在启动时继承得到
  • 文件创建模式掩码,使用 umask 设置或是从 shell 的父进程中继承得到
  • 当前陷阱,用 trap 设置
  • shell 参数,使用变量赋值或者 set 设置,或者是从父进程的环境中继承得到
  • shell 函数,在执行中定义或者是从父进程的环境中继承得到
  • 设为允许的选项,在执行时设置 (要么是默认允许的,要么是命令行给出的) 或者是用 set 设置
  • 用 shopt 设为允许的选项
  • 用 alias 定义的 shell 别名
  • 各种进程号,包含后台作业的进程号,$$ 的值,以及 $PPID 的值当并非 shell 函数或内置命令的简单命令执行时,它在一个由下述内容组成的单独的执行环境中启动。除非另外说明,值都是从 shell 中继承的。
    • shell 打开的文件,加上对命令使用重定向修改和添加的文件
    • 当前工作目录
    • 文件创建模式掩码
    • 标记为导出 (export) 的 shell 变量,以及传递到环境中为这个命令导出的变量
    • shell 捕捉的陷阱被重置为从 shell 的父进程中继承的值,shell 忽略的陷阱也被忽略

在单独的环境中启动的命令不能影响 shell 的执行环境。 命令替换和异步命令都在子 shell 环境中执行。子 shell 环境是原有 shell环境的赋值,但 shell 捕捉的陷阱被重置为 shell 启动时从父进程中继承的值。 作为管道一部分来执行的内建命令也在一个子 shell 环境中执行。对子 shell环境所作修改不能影响到原有 shell 的执行环境。 如果命令后面是 & 并且没有启用作业控制,命令的默认标准输入将是空文件/dev/null。否则,被执行的命令从调用它的 shell 中继承被重定向修改的文件描述符。

环境

当一个程序执行时,它被赋予一个字符串数组,成为环境。它是一个名称-值对的列表,形式是 “name=value” .shell 提供了多种操作环境的方法。启动时,shell 扫描自身的环境,为每个找到的名字创建一个参数,自动地将它标记为 export(向子进程导出的)。被执行的命令继承了这个环境。 export和 declare -x命令允许参数和函数被加入到环境中或从环境中删除。如果环境中参数的值被修改,新值成为环境的一部分,替换了旧值。所有被执行的命令继承的环境包含 shell 的初始环境 (可能值被修改过),减去被 unset命令删除的,加上通过 export和 declare -x命令添加的部分。可以在任何 simple command或函数的环境中设定暂时有效的参数,只要将参数赋值放在命令前面就可以了。这些赋值语句只在这个命令的环境中有效。如果设置了内建命令 set的 -k选项, 所有的变量赋值都将放到命令的环境中,不仅是在命令名前面的那些。当 bash执行一个外部命令时,变量 _被设置为命令的文件全名,然后被传递到命令的环境之中。

退出状态(“EXIT STATUS”)

从 shell 的角度看,一个命令退出状态是 0 意味着成功退出。退出状态是 0 表明成功。非零状态值表明失败。当命令收到 fatal signal N退出时,bash 使用 128+N 作为它的退出状态。 如果没有找到命令,为执行它而创建的子进程返回 127。如果找到了命令但是文件不可执行,返回状态是 126。如果命令由于扩展或重定向错误而失败,退出状态大于零。 shell 内建命令如果成功返回 0(true),执行时出错则返回非零 (false)。所有内建命令返回 2 来指示不正确的用法。Bash 自身返回最后执行的命令的退出状态,除非发生了语法错误,这时它返回非零值。

信号

如果 bash 是交互的,没有设定任何陷阱,它忽略 SIGTERM(这样 kill 0 不会杀掉交互的 shell)。 SIGINT被捕获并处理 (从而使内建命令 wait 可以中断)。在所有情况下,bash 忽略 SIGQUIT 。 如果正在使用作业控制, bash忽略 SIGTTIN , SIGTTOU ,和 SIGTSTP . bash 开始的并行作业的信号处理句柄都设置为 shell 从父进程中继承的值。如果不是正在使用作业控制,异步命令还忽略 SIGINT和 SIGQUIT 。 作为命令替换结果运行的命令忽略键盘产生的作业控制信号 SIGTTIN , SIGTTOU ,和 SIGTSTP . 如果收到信号 SIGHUP,shell 默认退出。在退出前,交互的 shell 向所有作业,运行的或停止的,发送 SIGHUP信号。shell 向停止的作业发出 SIGCONT信号来保证它们会收到 SIGHUP . 要阻止 shell 向特定的作业发送信号,应当使用内建命令 disown将作业从作业表中删除或者使用 “disown -h” 来标记为不接受 SIGHUP。 如果使用 shopt设置了 shell 选项 huponexit,在交互的登录 shell 退出时 bash向所有作业发出 SIGHUP信号。 当 bash 等待命令执行结束时,如果收到已设置了陷阱的信号,陷阱将不会执行,直到命令结束。 当 bash 通过内建命令 wait 等待异步命令时,如果收到已设置了陷阱的信号,将使得内建命令 wait 立即以大于 128 的状态值返回。接着,陷阱将立即被执行。

作业控制

作业控制指的是可以选择挂起进程执行,并且可以在之后继续执行的能力。用户一般在交互的人机界面中使用这种功能。界面是由系统的终端驱动和 bash 共同提供的。 shell 将每个管道分配给一个作业job。它保存一个当前运行的作业表,可以用 jobs命令来列出。当 bash启动一个异步的作业时 (后台执行),它输出这样的一行: [1] 25647 表明这个作业的作业号是 1,与作业相关连的管道中最后一个进程的进程ID是 15647。管道中所有进程都是同一个作业的成员。 Bash使用 作业概念作为作业控制的基础。为简化作业控制的用户界面的实现,操作系统负责管理当前终端的进程组的概念。这个进程组的成员(进程组 ID 是当前终端进程组 ID 的进程) 可以收到键盘产生的信号,例如 SIGINT .这些进程被称为 foreground (前台的)。 Background (后台的)进程是那些进程组 ID 与终端不同的进程;这些进程不会收到键盘产生的信号。只有前台进程可以从终端读或向终端写。后台进程试图读/写终端时,将收到终端驱动程序发送的 SIGTTIN (SIGTTOU)信号。这个信号如果没有加以捕捉,将挂起这个进程。 如果 bash运行其上的操作系统支持作业控制, bash会包含使用它的设施。在一个进程正在运行的时候键入 suspend 挂起字符 (通常是 ^Z ,Control-Z) 将使这个进程暂停,将控制权还给 bash . 输入 “delayed suspend”, 延时挂起字符 (通常是 ^Y ,Control-Y) 将使这个进程在试图从终端读取输入时暂停,将控制权还给 bash .用户接下来可以控制此作业的状态,使用 bg命令使它在后台继续运行, fg命令使它在前台继续运行,或 kill命令将它杀死。^Z 会立即起作用,并且还有使等待中的输出和输入被忽略的附加副作用。有很多方法来指代 shell 中的作业。字符 %可以引入作业名。编号为 n的作业可以用 %n的形式来指代。作业也可以用启动它的名称的前缀,或者命令行中的子字符串来指代。例如, %ce指代一个暂停的 ce作业。如果前缀匹配多于一个作业, bash报错。另一方面,使用 %?ce ,可以指代任何命令行中包含字符串 ce的作业。如果子字符串匹配多于一个作业, bash报错。符号 %%和 %+指代 shell 意义上的 “current job”,当前作业,也就是前台被暂停的最后一个作业,或者是在后台启动的作业。 “previous job”,前一作业可以使用 %- 来指代。在有关作业的输出信息中 (例如,命令 jobs的输出),当前作业总是被标记为 + ,前一作业标记为 - . 简单地给出作业名,可以用来把它放到前台: %1是fg %1的同义词,将作业 1 从后台放到前台。类似的, %1 &在后台恢复作业 1,与bg %1等价。 当某个作业改变状态时,shell 立即可以得知。通常, bash等待直到要输出一个提示符时,才会报告作业的状态变化,从而不会打断其他输出。如果启用了内建命令 set的 -b选项, bash将立即报告这些变化。对 SIGCHLD信号的陷阱将在每个子进程退出时执行。如果在作业暂停时试图退出 bash,shell 打印一条警告消息。命令 jobs可能被用来检查作业的状态。如果再次试图退出,中间没有其他命令,shell 不会打印其他警告,暂停的作业将终止。

shell 内建命令

除非另外说明,这一章介绍的内建命令如果接受 -引导的选项,那么它也接受 –作为参数,来指示选项的结束。[arguments]没有效果;这个命令除了扩展 arguments并且作任何指定的重定向之外,不做任何事。退出时返回0。

|命令|效果| |:—|:—| |. filename [arguments]|| |source filename [arguments]|读取并在当前 shell 环境中执行 filename中的命令,返回 filename中最后一个命令的返回状态。如果 filename中不包含斜杠,系统将在 PATH中查找包含 filename 的目录。在 PATH中搜索的文件不必是可执行的。如果 bash 不是运行于 posix mode,当 PATH中找不到文件时会在当前目录搜索。如果 shopt内建命令的 sourcepath选项被关闭, PATH将不会被搜索。如果有任何 arguments ,它们成为filename 的位置参数,否则位置参数不发生变化。返回状态是脚本中最后一个命令退出时的状态。没有执行命令则返回0,没有找到或不能读取 filename时返回false。| |alias [-p] [name[=value] ...]|不带参数或者带 -p参数运行时将在标准输出以格式alias name=value 给出别名列表。如果有参数,将创建提供了 value 的 name 的别名。value 中尾部的空格使得别名被扩展时,下一个词做别名替换。对于参数列表中的每一个 name,如果 value 没有给出,这个别名的名称和值会被打印出来。返回 true 除非 name 没有定义为别名。| |bg [jobspec]|使挂起的程序 jobspec 在后台继续执行,就好像它是用 &启动的一样。如果没有指定 jobspec,shell 意义上的current job 当前作业 将被使用。 返回0,除非当前禁止了作业控制,或者在允许作业控制,但是没有找到 jobspec ,或者它不是在作业控制下启动的时候。| |bind [-m keymap] [-lpsvPSV] 0|可选的 keymap名称是emacs, emacs-standard, emacs-meta, emacs-ctlx, vi,vi-move, vi-command,还有 vi-insert 。vi 和 vi-command 等价; emacs 和 emacs-standard 等价。 -l列出所有的 readline 功能。 -p以程序可读的方式显示 readline 功能名称和关联 -P列出当前 readline 功能名称和关联。 -v以程序可读的方式显示 readline 变量名称和值 -V列出当前 readline 变量和值。 -s以程序可读的方式显示 readline 键序列和对应的宏 -S显示 readline 宏对应的键序列和他们输出的字符串。返回值是0,除非给出了一个不能识别的选项或是产生了一个错误。| |bind [-m keymap] [-q function] [-u function] [-r keyseq]|-q function查询那些键将执行function,-u function取消所有关联到 function 的键。 -r keyseq取消当前任何 keyseq 的关联。| |bind [-m keymap] -f filename|从 filename 中读取键序列| |bind [-m keymap] -x keyseq:shell-command|使 shell-command 在 keyseq 按下时被执行| |break [n]|从一个 for , while , until ,或者 select循环退出。如果指定了 n ,就跳出 n 层循环。 n必须 >= 1。如果 n比当前循环层数还要大,将跳出所有循环。返回值是0,除非执行 break 的时候 shell 不是在执行一个循环。| |builtin shell-builtin [arguments]|执行指定的 shell 内建命令,传递 arguments,返回命令的返回值。这在定义了一个和 shell 内建命令同名的函数时很有用,在那个函数中使用它来执行相应的功能。cd 命令常以这种方式重新定义。返回状态是 false,如果指定的 shell-builtin并不是一个 shell 内建命令。| |cd [-L|-P] [dir]|改变当前路径到 dir。这个变量的默认值是 HOME目录。环境变量 CDPATH定义了包含 dir 的搜索路径。在 CDPATH中可选的路径名以冒号(:) 分隔。 CDPATH中的空路径名与当前路径相同,就是 .. 如果 目录名以斜杠 (/) 起始,那么 CDPATH不会被使用。 -P选项是说使用物理路径结构而不是跟随符号链接, -L选项强制跟随符号链接。另外,选项 -与 $OLDPWD 是相同的。返回值是 true ,如果成功地改变了目录;否则是 false。| |command [-pVv] command [arg ...]|运行 command,使用 args作为参数,禁止通常的查找 shell 函数的过程。只有内建命令或者 PATH中包含的命令可以执行。如果给出 -p参数, command的查找是以 PATH的默认值进行的。这样可以保证找到所有的标准工具。如果给出 -V或者 -v选项,关于 command的说明将被打印出来。 -v选项使得表述这个命令的词,或者要执行 command需要执行的文件显示出来; -V选项给出更详细的描述。如果给出 -V或者 -v选项,退出状态在找到了 command的情况下0,没找到就是1。如果没有提供选项,并且产生了错误或者 command没有找到,退出状态就是127。否则, 退出状态是 command的退出状态。| |compgen [option] [word]|根据 option 为 word 产生可能的补全。option 是内建命令 complete接受的任何选项,除了 -p 和 -r,将匹配结果写到标准输出。当使用 -F 或 -C 选项时,可编程补全功能所设置的多数shell 变量如果存在,其值将不再有用。 产生的匹配与可编程补全代码根据补全规则加上相同的标志直接产生的结果相同。如果指定了 word,只有匹配 word 的补全结果将被显示出来。 返回值为真,除非提供了非法的选项,或者没有产生匹配。| |complete [-abcdefgjksuv] [-o comp-option] [-A action] [-G globpat] [-W wordlist] [-P prefix] [-S suffix] [-X filterpat] [-F function] [-C command] name [name ...]|| |complete -pr [name ...]|指定每个 name 的参数应当如何被补全。如果给出了 -p 选项,或者没有选项给出,现有的补全规则将被显示出来,以一种可以重用为输入的格式显示。-r 选项将一个针对每个 name 的补全规则删除。或者,如果没有给出 name,将删除所有补全规则。 1尝试词的补全时,应用这些补全规则的过程在上面Programmable Completion(可编程补全) 中详述。 1其他选项,如果给出的话,具有下列意义。-G, -W, 和 -X 选项的参数 (如果需要的话,还包括 -P 和 -S 选项) 应当被引用,避免在执行内建命令 complete之前被扩展。 0 -o comp-optioncomp-option 控制着 compspec 除了简单地产生补全之外的多种行为。comp-option 可以是如下之一: default使用 readline 的默认文件名补全,如果 compspec 没有得到匹配。 dirnames进行目录名补全,如果 compspec 没有得到匹配。 filenames告诉 readline,compspec 产生了文件名,使它可以进行任何文件名专用的处理(例如,给目录名加上斜杠或消除尾部空白)。主要用于 shell 函数。 nospace告诉 readline 不要向补全的词在行的最后添加一个空格 (这是默认行为)。 -A actionaction 可以是下列之一,来产生一系列可能的补全结果: alias起别名。也可以用 -a 指定。 arrayvar数组变量名。 bindingReadline 按键关联。 builtinshell 内建命令的名称。也可以用 -b 指定。 command命令名。也可以用 -c 指定。 directory目录名。也可以用 -d 指定。 disabled被禁用的内建命令名称。 enabled启用的内建命令名称。 export被导出的 shell 变量名称。也可以用 -e 指定。 file文件名。也可以用 -f 指定。 functionshell 函数的名称。 group组名。也可以用 -g 指定。 helptopic内建命令 help 接受的帮助主题。 hostname主机名,从环境变量 HOSTFILE指定的文件中得到。 job作业名,如果作业控制被激活的话。也可以用 -j 指定。 keywordshell 保留字。也可以用 -k 指定。 running正在运行的作业名,如果作业控制被激活的话。 service服务名。也可以用 -s 指定。 setopt内建命令 set 的 -o 选项的有效参数。 shopt内建命令 shopt 接受的 shell 选项名。 signal信号名。 stopped停止的作业名,如果作业控制被激活的话。 user用户名。也可以用 -u 指定。 variableshell 变量的名称。也可以用 -v 指定。 -G globpat文件名扩展模式 globpat 被扩展,产生可能的补全。 -W wordlistwordlist 被使用 IFS特殊变量中的字符作为定界符来拆分,每个结果的词被扩展。可能的补全是结果列表中匹配要补全的词的那一些。 -C commandcommand 将在一个子 shell 环境中执行,它的结果用作可能的补全。 -F functionshell 函数 function 将在当前 shell 环境中执行。当它结束时,可能的补全可以从数组元素 COMPREPLY中得到。 -X filterpatfilterpat 是一个模式,用于文件名扩展。所有前面的选项和参数产生的可能的补全都要经过这一步处理,每一个匹配 filterpat 的补全都被从列表中删除。为 filterpat 加上前导 ! 使模式意义相反;这种情况下,所有不匹配 filterpat 的模式被删除。 -P prefix在所有其他选项都处理过之后,prefix 被加到每个可能的补全前面。 -S suffix在所有其他选项都处理过之后,suffix 被加到每个可能的补全后面。返回值为真,除非给出了非法的选项,给出除 -p 和 -r 之外的某个选项时没有给出 name 参数,试图删除一条 name 的补全规则但是规则不存在,或者添加补全规则时出错。| |continue [n]|复位到外层 for , while , until ,或 select循环的下一次开始。如果指定了 n,复位到向外第 n 层循环的开始。 n必须 >= 1。如果 n比外部循环的层数要多,将复位到最外层的循环。返回值是 0,除非执行 continue时,shell 不是在循环之中。| |declare [-afFirtx] [-p] [name[=value]]|| |typeset [-afFirtx] [-p] [name[=value]]|声明变量且/或设置它们的属性。如果没有给出 name 则显示变量的值。选项 -p将显示每个名称 name 的属性和值。当使用 -p时,其他选项被忽略。选项 -F禁止显示函数定义;只有函数名和属性会被显示。 -F选项暗含 -f .下列选项可用来限制只输出具有指定属性的变量,或者为变量设置属性: -a每个 name 都是数组变量。 -f只使用函数名。 -i变量被当作一个整数;当变量被赋值时将进行算术运算。 -r使得 name 只读。这些名称不能再被后续的赋值语句赋值或取消定义。 -t设置每个 name 的 trace(跟踪) 属性。被跟踪的函数继承了调用者 shell 的 DEBUG 陷阱。trace 属性对变量没有特殊意义。 -x标记 name 为可以通过环境导出给后续命令。使用 +' 代替 -‘ 将关闭属性,特殊情况是 +a 不能用于销毁一个数组变量。当用于函数中时,它使得每个 name 成为局部的,就像使用了 local命令。返回值是 0,除非遇到了非法的选项,试图使用-f foo=bar定义函数,试图向只读变量赋值,试图向数组变量赋值但没有使用复合的赋值语法,name 之一不是有效的 shell 变量名,试图将数组变量的数组状态关闭,或者是试图使用 -f 显示一个不存在的函数。 | |dirs [-clpv] [+n] [-n]|没有选项时显示当前保存的目录。默认输出为一行,目录名用空格分开。可以使用 pushd命令将目录添加到列表, popd命令将列表中的条目删除。+n显示 dirs在不带选项执行时显示的列表的第 n 个条目,从 0 开始自左算起。-n显示 dirs在不带选项执行时显示的列表的第 n 个条目,从 0 开始自右算起。 -c删除所有条目,清空目录栈。 -l产生长列表;默认列表格式使用波浪线来表示个人目录。 -p输出目录栈,一行一个。 -v输出目录栈,一行一个,每个条目前面加上它在栈中的位置索引。返回值是 0,除非给出了非法的参数,或者 n 索引超出了目录栈的范围。| |disown [-ar] [-h] [jobspec ...]|没有选项时,每个 jobspec被从正在运行的作业表中删除。如果给出了 - 选项,每个 jobspec并不从表中删除,而是被标记,使得在 shell 接到 SIGHUP 信号时,不会向作业发出 SIGHUP信号。如果没有给出 jobspec,也没有给出 -a或者 -r选项,将使用当前作业。如果没有给出 jobspec,选项 -a意味着删除或标记所有作业;选项 -r不带 jobspec参数时限制操作只对正在运行的作业进行。返回值是 0,除非 jobspec不指定有效的作业。| |echo [-neE] [arg ...]|输出 arg,以空格分开,最后加一个新行符。返回值总是 0。如果指定了 -n,将不在尾部添加新行符。如果给出了 -e 选项,将允许解释下列反斜杠转义的字符。 -E选项禁止这些转义字符的解释,即使在默认解释它们的系统中也是如此。shell 选项 xpg_echo 可以用来在运行时判断 echo 是否默认展开这些转义字符。 echo不将 –作为选项的结束。 echo解释下列转义序列: \a、\b、\c(删除尾部换行)、\e(字符 Esc)、\f、\n、\r、\t、\v、\\、\0nnn、\nnn、\xHH| |enable [-adnps] [-f filename] [name ...]|允许或禁止 shell 内建命令。禁止一个内建命令使得磁盘上的与内建命令同名的文件得以运行,不必使用它的全路径,即使 shell 一般在搜索磁盘上的命令之前搜索内建命令。如果使用了 -n 选项,每个 name 都被禁止;否则,name 被允许。例如,要使用 PATH中搜索到的 test命令而不是 shell 内建的那一个,可以运行enable -n test.选项 -f意味着从共享库 filename中加载新的内建命令 name,如果系统支持动态加载的话。选项 -d将删除曾经用 -f 加载的内建命令。如果没有给出 name 参数,或者给出了 -p选项,将显示 shell 内建命令的列表。如果没有其他选项参数,这个列表只包含所有被允许的 shell 内建命令;如果给出了-n,将只显示被禁止的内建命令;如果给出了 -a,显示的列表中包含所有内建命令,还有命令是否被允许的指示;如果给出了 -s,输出被限制为 POSIX special 内建命令。返回值是 0,除非 name不是 shell 内建命令,或者从共享库中加载新的内建命令时出错。| |eval [arg ...]|arg 被读取并连结为单一的命令。这个命令然后被 shell 读取并执行,它的退出状态被作为 eval的值返回。如果没有 args ,或仅仅包含空参数, eval返回 0。| |exec [-cl] [-a name] [command [arguments]]|如果指定了 command,它将替换 shell。不会产生新的进程。 arguments成为 command 的参数。如果给出了 -l选项,shell 将在传递给 command的第 0 个参数前面加上一个连字符 (dash,-')。这样做和 login 相同。选项 -c使得命令 command在一个空环境中执行。如果给出了 -a,shell 会将 name作为第 0 个参数传递给要执行的命令。如果由于某种原因不能被执行,非交互的 shell 将退出,除非 shell 选项 execfail被设置为允许,这种情况下它返回失败。如果命令不能执行,交互的 shell 返回失败。如果没有指定 command任何重定向对当前 shell 发生作用,返回值是 0。如果发生重定向错误,返回状态是 1。| |exit [n]|使得 shell 以状态值 n 退出。如果忽略了 n,退出状态是最后执行的命令的退出状态。在 shell 终止前,对 EXIT的陷阱将被执行。| |export [-fn’] [name[=word]] … 0 export -p|给出的名称 names被标记为自动地导出到后续执行的命令的环境中。如果给出了 -f选项,名称 names指的是函数。如果没有给出 names,或者如果给出了 -p选项,将打印在这个 shell 中被导出的所有名字的列表。选项 -n使得以此为名的变量的导出属性被删除。 export返回 0,除非遇到了非法的选项,name 之一不是有效的 shell 变量名,或者给出了 -f选项,而 name不是一个函数。| |fc [-e ename] [-nlr] [first] [last] |命令修复。历史列表中从 first到 last范围内的命令都被选取。 First和 last可以指定为字符串 (可以定位最后一个以此字符串开始的命令) 或者数字 (历史列表中的索引,负数被当作相对当前命令号的偏移)。如果没有指定 last,它在列举时被设为当前命令 (因此fc -l -10将输出最后 10 条命令),其他情况下被设为 first。如果没有指定 first,它在编辑时被设为前一个命令,列举是设为 -16。 1选项 -n使得列举时不显示命令号码。选项 -r将命令顺序进行掉换。如果给出了 -l选项,命令将列举在标准输出上。否则,将启动 ename给出的编辑器,编辑包含这些命令的文件。如果没有给出 ename,将使用变量 FCEDIT的值,如果 FCEDIT没有定义就使用 EDITOR的值。如果仍然没有定义,将使用 vi。编辑结束后,被编辑的命令将回显并执行。返回值是 0,除非遇到了非法的选项,或 first或 last指定的历史行数超出了范围。如果给出了 -e选项,返回值是最后执行的命令的返回值,或着是失败,如果临时文件中的命令执行出错。| |fc -s [pat=rep] [cmd]|命令修复。command 在每个 pat 的实例被 rep 替换后都被重新执行。使用这种特性时可以起一个有用的别名: r=fc -s,这样输入 r cc将运行最后的以 cc开头的命令,输入 r将重新执行上一个命令。 返回状态是重新执行的命令,除非 cmd没有指定一个有效的历史行,这种情况下 fc返回失败。| |fg [jobspec]|将 jobspec恢复至前台,使它成为当前作业。如果 jobspec不存在,将使用 shell 意义上的当前作业 current job。返回值是被放到前台的命令的状态,或者是失败,如果在禁用作业控制时运行,或者在启用作业控制时运行,但 jobspec没有指定有效的作业,或 jobspec指定了没有使用作业控制的作业。| |getopts optstring name [args]|由 shell 程序用来处理位置参数。 optstring包含要识别的选项字符;如果某个字符跟随着冒号,那么这个选项需要一个参数,需要用空白和它隔离开。冒号和问号字符不能用作选项字符。每次它执行时, getopts将下一个选项放在 shell 变量 name 中,如果 name不存在就初始化它;下一个要处理的参数的索引放在变量 OPTIND中。每次 shell 或 shell 脚本被执行的时候 OPTIND被初始化为 1。当某个选项需要参数时, getopts将那个参数放到变量 OPTARG 中。shell 不会自动重置 OPTIND;在相同的 shell 中,如果要使用新的参数集合而需要多次调用 getopts时,必须手动重置它。当遇到选项结束的时候,getopts 以大于 0 的值退出。OPTIND 被设置为第一个非选项的参数的索引,name 被设置为 ?。 getopts通常解释位置参数,但是如果 args 中给出了更多参数, getopts将解释它们。 getopts能以两种方式报告错误。如果 optstring的第一个字符是冒号,将使用 silent安静的错误报告。通常的操作中,遇到非法选项或缺少选项的参数时将打印出诊断信息。如果变量 OPTERR被设置为 0,不会显示错误消息,即使 optstring的第一个字符不是冒号。如果发现了一个非法的选项, getopts向 name中置入 ?,并且如果不是安静模式的话,打印错误消息并取消 OPTARG的定义。如果 getopts是安静模式,找到的选项字符将置入 OPTARG,不会打印诊断消息。 如果没有找到需要的参数,并且 getopts不是安静模式,将向 name置入一个问号 ('?'),取消 OPTARG的定义,打印出诊断消息。如果 getopts是安静模式,那么将向 name置入一个冒号 (':') 并且 OPTARG将设置为找到的选项字符。 返回真,如果找到了指定的/未被指定的选项。它返回假,如果遇到了选项结束或者发生了错误。| |hash [-lr] [-p filename] [-dt] [name]|对于每个 name ,通过搜索 $PATH中的目录,找到命令的全路径名并记录它。如果给出了 -p选项,不会进行路径搜索,直接将 filename作为命令的全路径名。选项 -r使得 shell 忘记所有已记录的位置。选项 -d使得 shell 忘记已记录的 name 的位置。如果给出了 -t选项,每个 name 对应的全路径名被打印出来。如果给出多个name 作为 -t 的参数,name 将在已记录的全路径名之前被打印出来。选项 -l使得输出以一种可以重用为输入的格式显示。如果没有给出参数,或者只给出了 -l 选项,已记录的命令的信息将被打印出来。返回真,除非 name没有找到或给出了非法的选项。| |help [-s] [pattern]|显示关于内建命令的有用的信息。如果指定了 pattern (模式), help给出关于所有匹配 pattern的命令的详细帮助;否则所有内建命令的帮助和 shell 控制结构将被打印出来。选项 -s 限制信息显示为简短的用法概要。返回 0,除非没有匹配 pattern的命令。| |history [n]|显示带行号的命令历史列表。列出的行中含有 *的已经被修改过。参数 n使得只显示最后 n行。| |history -c|清空历史列表,删除所有条目。| |history -d offset|删除 offset 位置的历史条目| |history -anrw [filename]|如果给出了 filename,它被用做历史文件名;没有的话,将使用 HISTFILE的值作为历史文件名。选项如果给出,-a将新的历史条目 (自当前 bash 会话开始输入的历史命令)追加到历史文件中。 -n将尚未从历史文件中读取的历史条目读入当前历史列表。这些行是当前bash 会话开始之后,才追加到历史文件中的行。 -r读取历史文件的内容,使用它们作为当前历史。 -w将当前历史列表写入历史文件,覆盖历史文件的原有内容。| |history -p arg [arg …]|对后续的 args 进行历史替换,在标准输出上显示结果。不会将结果存入历史列表。每个 args 都必须被引用,来禁止普通的命令扩展。| |history -s arg [arg …]|将 args保存到历史列表中,作为单独的条目。历史列表中的最后一个命令在添加 args之前被删除。| |jobs [-lnprs] [ jobspec … ]|列出正在运行的作业。选项具有下列意义: 0 -l普通信息之外,列出进程ID。 -p只列出作业的进程组 leader 的进程ID。 -n只显示从上次用户得知它们的状态之后,状态发生改变的作业的信息。 -r限制只输出正在运行的作业。 -s限制只输出停止的作业。如果给出了 jobspec输出被限制为仅此作业的信息。返回 0,除非遇到了非法的选项或给出了非法的 jobspec。| |jobs -x command [ args … ]|将 command或 args中的任何 jobspec替换为相应的进程组ID,执行 command,传递参数 args给它并返回它的退出状态。| |kill [-s sigspec | -n signum | -sigspec] [pid | jobspec] …|| |kill -l [sigspec | exit_status]|向以 pid或 jobspec为名的进程发送名为 sigspec或 signum的信号。 sigspec可以是一个信号名称,类似 SIGKILL或信号编号; signum是一个信号编号。如果 sigspec是一个信号名称,那么可以有,也可以没有 SIG前缀。如果没有给出 sigspec,那么假设是 SIGTERM。参数 -l将列出所有信号的名称。如果给出 -l时还有任何参数,将列出参数对应的信号名称,返回状态 0。 -l的 exit_status 参数是一个数字,指定了一个信号编号或被信号终止的进程的退出状态值。 kill返回真,如果至少成功发送了一个信号,或者返回假,如果发生了错误或遇到了非法的选项。| |let arg [arg …]|每个 arg都是要求值的算术表达式。如果最后一个参数 arg求值结果是 0, let返回 1;否则返回 0。| |local [option] [name[=value] …]|对每个参数将创建一个名为 name 的局部变量并赋予值 value。option 可以是任何 declare 接受的值。当 local用于函数内部时,它使得变量 name作用域局限于函数和它的子进程。没有操作数时, local将局部变量的列表写到标准输出。不在函数内部使用 local会导致出错。返回 0,除非在函数之外使用了 local,给出了非法的 name,或者 name 是一个只读的变量。| |logout|退出登录 shell。| |popd [-n] [+n] [-n]|从目录栈中删除条目。没有参数的话,从栈中删除顶层目录,执行 cd切换到新的顶层目录。如果给出了参数,有下列的含义: 0+n删除 dirs给出的列表中从左数第 n 个条目 (从 0 算起)。例如: popd +0 删除第一个目录, popd +1第二个。-n删除 dirs给出的列表中从右数第 n 个条目 (从 0 算起)。例如: popd -0删除最后一个目录, popd -1删除倒数第二个。 -n阻止从栈中删除目录之后改变目录,这时只对栈进行操作。如果命令 popd成功,还要执行一个 dirs,返回 0。 popd返回假,如果遇到了非法的选项,目录栈为空,指定了目录栈中不存在的条目,或者改变目录失败。| |printf format [argument]|在 format 控制下将格式化的 arguments 写到标准输出。format 是一个字符串,包含三种类型的对象:普通字符,被简单地复制到标准输出,转义字符,被转换并复制到标准输出,格式说明,每一个都使得相邻的下一个 argument 被打印出来。在标准的 printf格式之外,%b 使得 printf 展开相应arguments 中的反斜杠转义序列,%q 使得 printf 将相应的 argument 以一种可以重用为 shell 输入的格式输出。 format 在需要时被重用,以处理所有的 arguments。如果 format 需要比所提供的更多的 arguments,多出的格式说明视为已经提供了相应的 0 值或空字符串。成功的话返回值是 0,失败则是非 0 值。| |pushd [-n] [dir]|| |pushd [-n] [+n] [-n]|将目录推入目录栈,或者轮换栈中的内容,使栈的顶部成为当前工作目录。没有参数时,交换顶部两个目录,返回 0,除非目录栈为空。如果给出了参数,它们有如下含义: 0+n轮换栈中内容,使得 dirs给出的列表中从左数第 n 个目录 (从 0 数起) 成为目录栈的顶部。-n轮换栈中内容,使得 dirs给出的列表中从右数第 n 个目录 (从 0 数起) 成为目录栈的顶部。 -n阻止向栈中添加目录之后改变目录,这时只对栈进行操作。 dir添加 dir到栈顶,使得它成为新的当前工作目录。如果命令 pushd成功,还要执行一个 dirs。如果使用第一种形式, pushd返回 0,除非 cd 切换到目录 dir失败。使用第二中形式时, pushd返回 0,除非目录栈为空,指定了目录栈中不存在的元素,或者切换到指定的新的当前目录失败。| |pwd [-LP]|打印当前工作目录的绝对路径名。如果给出了 -P选项,或者设置了内建命令 set的 -o physical选项,打印出的路径名中不会包含符号链接。如果使用了 -L选项,打印出的路径中可能包含符号链接。返回 0,除非在读取当前目录名时出错或给出了非法的选项。| |read [-ers] [-u fd] [-t timeout] [-a aname] [-p prompt] [-n nchars] [-d delim] [name …]|从标准输入读入一行,或从 -u 选项的参数中给出的文件描述符 fd 中读取,第一个词被赋予第一个 name ,第二个词被赋予第二个 name ,以此类推,多余的词和其间的分隔符被赋予最后一个 name .如果从输入流读入的词数比名称数少,剩余的名称被赋予空值。 IFS中的字符被用来将行拆分成词。反斜杠字符 (\) 被用于删除读取的下一字符的特殊含义,以及续行。如果给出了选项,将包含下列含义: 0 -a aname词被赋以数组变量 aname的连续的下标,从 0 开始。在赋新值之前, aname被取消定义。其他 name 参数被忽略。 -d delimdelim 的第一个字符被用于结束输入行,而不是新行符。 -e如果标准输入来自终端,将使用 readline来获得输入行。 -n nchars 读入 nchars 个字符后返回,而不是等待一整行输入。 -p prompt读取任何输入之前,在标准错误显示提示 prompt,末尾没有新行符。提示只有在输入来自终端时才会显示。 -r反斜杠不作为转义字符。反斜杠被认为行的一部分。特殊地,一对反斜杠-新行符不作为续行。 -s安静模式。如果输入来自终端,字符将不会回显。 -t timeout使得 read 超时并返回失败,如果在 timeout 秒内没有读入完整的一行输入。如果 read 不是从终端或管道读取输入,那么这个选项无效。如果没有给出 names,读取的一行将赋予变量 REPLY 。返回值是 0,除非遇到了 EOF,超时或给出了非法的文件描述符作为 -u 的参数。| |readonly [-apf] [name …]|给出的 name 将被标记为只读的; names的值不能被后来的赋值语句改变。如果给出了 -f选项,names 对应的函数也被标记。选项 -a限制变量只能是数组类型。如果没有给出 name参数,或者如果给出了 -p选项,将打印所有只读的名称。选项 -p使得输出以一种可以被重新用作输入的格式显示。返回值是 0,除非遇到了非法的选项, names之一不是有效的 shell 变量名,或选项 -f中给出的 name不是一个函数。| |return [n]|使得一个函数以指定值 n退出。如果忽略了 n,返回状态是函数体中执行的最后一个命令的退出状态。如果在函数外使用,但是是在一个以 .(source) 命令执行的脚本内,它使得 shell 中止执行脚本,返回 n或脚本中执行的最后一个命令的退出状态。如果在函数外使用,并且不是在以 . 执行的脚本内,返回状态是假。| |set [–abefhkmnptuvxBCHP] [-o option] [arg …]|不带选项时,shell 变量的名称和值将以一种可以重用为输入的格式显示。输出根据当前语言环境进行排序。指定了选项的时候,它们设置或取消了 shell 的属性。处理完选项之后剩余的任何参数都被作为位置参数的值被赋值,分别赋予 $1 , $2 , ... $n .如果给出了选项,那么具有以下含义: -a自动将被修改或创建的变量和函数标志为导出至后续命令的环境中。 -b后台作业结束时立即报告状态,而不是在下次显示主提示符前报告。只有在启用作业控制时才有效。 -e立即退出,如果简单命令以非零值退出。shell 不会退出,如果失败的命令是 until或 while循环的一部分, if语句的一部分, &&或 ||序列的一部分,或者命令的返回值是由 ! 翻转得到。针对 ERR 的陷阱,如果设置的话,将在 shell 退出前执行。 -f禁止路径扩展。 -h在查找并执行命令时,记住它们的位置。这是默认启用的。 -k所有以赋值语句形式出现的参数都被加入到命令执行的环境中,不仅是命令名前面那些。 -m监视模式。作业控制被启用。在支持这个选项的系统中,它在交互 shell 中是默认启用的 。后台进程在单独的进程组中运行,结束时将打印出包含它们退出状态的一行信息。 -n读取命令,但不执行。这可以用在检查 shell 脚本中的语法错误。交互 shell 中它被忽略。 -o option-nameoption-name 可以是如下之一: allexport与 -a相同。 braceexpand与 -B相同。 emacs使用 emacs 样式的命令行编辑界面。这个选项在交互 shell 中默认启用,除非 shell 以 --noediting选项启动。 errexit与 -e相同。 hashall与 -h相同。 histexpand与 -H相同。 history允许记录命令历史,如上述 HISTORY中的描述。这个选项在交互 shell 中默认启用。 ignoreeof它的效果是好像已经执行了 shell 命令IGNOREEOF=10一样 。 keyword与 -k相同。 monitor与 -m相同。 noclobber与 -C相同。 noexec与 -n相同。 noglob与 -f 相同。 nolog当前被忽略。 notify与 -b相同。 nounset与 -u 相同。 onecmd与 -t 相同。 physical与 -P 相同。 posix如果默认操作与 POSIX 1003.2 不同的话,改变 bash的行为,来满足标准 (posix mode)。 privileged与 -p相同。 verbose与 -v 相同。 vi使用 vi 样式的命令行编辑界面。 xtrace与 -x 相同。 .5如果给出了不带 option-name 的 -o选项,当前选项的值将被打印出来。如果给出了不带 option-name 的 +o选项,将在标准输出显示一系列可以重建当前选项设定的 set命令。 -p打开 privileged mode (特权模式)。在这个模式中,不会处理 $ENV和 $BASH_ENV文件,shell 函数不会从环境中继承,环境中如果有变量 SHELLOPTS,也将被忽略。如果 shell 启动时的有效用户(组) ID 与真实用户(组) ID 不同,并且没有给出 -p 选项,将执行这些操作,有效用户 ID 将设置为真实用户 ID。如果启动是给出了 -p 选项,有效用户 ID 不会被重置。将这个选项关闭使得有效用户和组 ID 被设置为真实用户和组 ID。 -t读取并执行一个命令之后退出。 -u在进行参数扩展时,将未定义的变量作为错误。如果试图扩展未定义的变量,shell 将输出一条错误消息;如果是非交互的 shell,shell 将以非零值退出。 -v在读取输入的同时打印出来。 -x扩展每个简单命令之后,显示 PS4的值,接着显示命令和它扩展后的参数。 -Bshell 执行花括号扩展。这是默认允许的。 -C如果设置的话, bash使用重定向操作符 > , >& ,和 <>时,不会覆盖已存在的文件。可以使用重定向操作符 >|代替 >来创建输出文件,从而绕过这个限制。 -H允许Enable !样式的历史替换。在交互 shell 中这个选项是默认启用的。 -P如果设置的话,shell 在执行类似 cd的,改变当前工作目录的命令时,不会跟随符号连接。它将使用物理的目录结构来代替。默认情况下, bash在执行改变当前目录的命令时跟随路径的逻辑链。 --如果这个选项没有参数,将取消位置参数的定义。否则,位置参数将设置为arg,即使它们以 -开始。 -通知信号的结束,使得所有剩余的 arg 被赋予位置参数。 -x和 -v选项被关闭。如果没有 arg,位置参数将不会改变。这个选项默认是关闭的,除非另外说明。使用 + 而不是 - 使得这些选项被关闭。选项都可以作为参数,在 shell 启动时指定。当前的选项集合可以从 $- 找到。返回值总是真,除非遇到了非法的选项。| |shift [n]|从 n+1 ... 开始的选项被重命名为 $1 ....从 $# 向下直到 $# -n+1 的选项被取消定义。 n必须是非负整数,小于或等于 $# 。如果 n是 0,不会改变参数。如果没有给出 n,就假定它是 1。如果 n比 $# 大,位置参数不会改变。返回值大于 0,如果 n比 $# 大或小于 0;否则返回 0。| |shopt [-pqsu] [-o] [optname …]|对于控制可选的 shell 行为的变量,改变它们的值。没有选项或者有 -p选项时,将显示所有可设置的选项列表,以及它们是否已经设置的指示。-p 使得输出以一种可以被重用为输入的形式显示。其他选项有如下含义: 0 -s允许(设置) 每个 optname。 -u禁止(取消) 每个 optname。 -q禁止通常的输出 (安静模式);返回状态指示了 optname 是否被设置。如果对 -q 给出了多个 optname 参数,如果所有 optname 都被允许,返回值就是 0;否则返回非零值。 -o限制 optname 的值为内建命令 set的 -o选项定义的值。如果使用 -s或 -u时没有给出 optname 参数,显示将分别限于被设置或被取消的选项。除非另外说明,shopt 选项默认被禁止(取消)。返回值在列出选项时是 0,如果所有 optname 都被允许的话,否则是非零值。当设置或取消选项时,返回值是 0,除非 optname 是非法的 shell 选项。shopt 选项的列表是: cdspell、checkhash、checkwinsize、cmdhist、execfail、expand_aliases、extglob、histappend、histreedit、histverify、hostcomplete、huponexit、interactive_comments、lithist、login_shell、mailwarn、no_empty_cmd_completion、nocaseglob、nullglob、progcomp、promptvars、restricted_shellshell、shift_verbose、sourcepath、xpg_echo。| |suspend [-f]|挂起 shell 的执行,直到收到一个 SIGCONT信号。选项 -f表示如果这是一个登录 shell,那么不要提示,直接挂起。返回值是 0,除非shell 是登录 shell 并且没有指定 -f,或者没有启用作业控制。| |test expr || |[ expr ]|返回状态值 0 或 1,根据条件表达式 expr的求值而定。每个操作符和操作数都必须是一个单独的参数。表达式使用上面 "条件表达式"中的操作构造。表达式可以用下列操作符结合,以优先级的降序列出。 ! expr值为真,如果 expr为假。 ( expr )返回 expr 的值。括号可以用来超越操作符的一般优先级。expr1 -a expr2值为真,如果 expr1和 expr2都为真。expr1 -o expr2值为真,如果 expr1或 expr2为真。test 和 [ 使用基于参数个数的一系列规则,对条件表达式进行求值。 无参表达式为假。1参数表达式为真,当且仅当参数非空。2参数表达式如果第一个参数是 !,表达式为真,当且仅当第二个参数为空。如果第一个参数是上面 "条件表达式"中列出的单目条件运算符之一,表达式为真,当且仅当单目测试为真。如果第一个参数不是合法的单目条件运算符,表达式为假。3参数表达式如果第二个参数是上面 "条件表达式"中列出的二进制条件操作符之一,表达式的结果是使用第一和第三个参数作为操作数的二进制测试的结果。如果第一个参数是 !,表达式值是使用第二和第三个参数进行双参数测试的结果取反。如果第一个参数是 (,第三个参数是 ),结果是对第二个参数进行单参数测试的结果。否则,表达式为假。这种情况下 -a 和 -o 操作符被认为二进制操作符。4参数表达式如果第一个参数是 !,结果是由剩余参数组成的三参数表达式结果取反。否则,表达式被根据上面列出的优先级规则解释并执行。| |times|对 shell 以及 shell 运行的进程,打印累计的用户和系统时间。返回状态是 0。| |trap [-lp] [arg] [sigspec …]|当 shell 收到信号 sigspec时,命令 arg将被读取并执行。如果没有给出 arg或者给出的是 - ,所有指定的信号被设置为它们的初始值 (进入 shell 时它们的值)。如果 arg是空字符串, sigspec指定的信号被 shell 和它启动的命令忽略。如果 arg不存在,并且给出了 -p那么与每个 sigspec相关联的陷阱命令将被显示出来。如果没有给出任何参数,或只给出了 -p, trap将打印出与每个信号编号相关的命令列表。每个 sigspec可以是 <signal.h> 定义的信号名,或是一个信号编号。如果 sigspec是 EXIT(0),命令 arg将在 shell 退出时执行。如果 sigspec是 DEBUG ,命令 arg将在每个简单命令之后执行。如果 sigspec是 ERR ,命令 arg将在任何命令以非零值退出时执行。如果失败的命令是 until或 while循环的一部分, if语句的一部分, &&或 &#124;&#124;序列的一部分,或者命令的返回值是通过 !转化而来, ERR陷阱将不会执行。选项 -l使得 shell 打印信号名和对应编号的列表。shell 忽略的信号不能被捕捉或重置。在子进程中,被捕捉的信号在进程创建时被重置为初始值。返回值为假,如果 sigspec非法;否则 trap返回真。| |type [-aftpP] name [name …]|没有选项时,指示每个 name将如何被解释,如果用作一个命令名。如果使用了 -t选项, 打印一个字符串,内容是如下之一: alias , keyword , function , builtin ,或 file ,如果 name分别是一个别名,shell 保留字,函数,内建命令或磁盘文件。如果没有找到 name,那么不会打印任何东西,返回退出状态假。如果使用了 -p选项, type返回如果 name作为命令名,将被执行的磁盘文件名;或者返回空,如果type -t name不会返回 file .选项 -P选项强制对每个 name 搜索 PATH,即使type -t name不会返回 file .如果命令在散列中, -p和 -P将打印散列的值,而不是 PATH中首先出现的那一个文件。如果使用了 -a选项, type打印所有包含可执行的名称 name 的场合。结果包括别名和函数,当且仅当没有同时使用 -p选项。使用 -a时不会查找散列中的命令表。选项 -f阻止 shell 进行查找,就像在内建命令 command 中一样。 返回真,如果找到了任何参数。什么都没找到则返回假。| |ulimit [-SHacdflmnpstuv [limit]]|在支持它的系统上,对 shell 和它启动的进程,提供对可用资源的控制。选项 -H 和 -S 指定为所给资源设定的硬性和柔性限额。硬性限额在设置后不能增加;柔性限额可以增加,直到与硬性限额相等。如果没有给出 -H 或 -S 选项,将同时设置硬性和柔性限额。 limit的值可以是一个数字,单位是指定资源的单元值,或者是特殊值 hard , soft ,或 unlimited之一,意思分别是当前硬性限额,当前柔性限额和没有限额。如果忽略了 limit,将打印出当前对资源的柔性限额值,除非给出了 -H 选项。当指定多于一个资源时,限额名称和单位将在值之前打印出来。其他选项按照如下意义解释: -a报告所有当前限额 -ccore 文件的最大值 -d进程数据段的最大值 -fshell 创建的文件的最大值 -l内存中可以锁定的最大值 -m常驻内存的最大值 -n打开的文件描述符最大个数 (大多数系统不允许设置这个值) -p管道大小,以 512 字节的块为单位 (这个值可能不能设置) -s栈的最大值 -tcpu 时间总数的最大值,以秒计 -u用户可以运行的最大进程数 -vshell 可用的虚拟内存总量的最大值如果给出了 limit,它将是指定资源的新限额 (选项 -a只显示它们)。如果没有给出选项,则假设有 -f。值的递增间隔是 1024 字节,除了 -t 单位是 秒, -p单位是 512 字节的块个数, -n和 -u是不可调节的值。返回 0,除非给出了非法的选项或参数,或者在设置新的限额时发生了错误。| |umask [-p] [-S] [mode]|用户创建文件的掩码被设置为 mode .如果 mode以数字开始,它被解释为一个八进制数;否则被解释为类似于 chmod接受的符号形式的模式掩码。如果忽略了 mode,将打印当前掩码值。选项 -S使得掩码以符号形式打印;默认输出是八进制数。如果给出了 -p选项,并且忽略了 mode,输出将是一种可以重用为输入的形式。返回值是 0,如果成功改变了模式,或者没有给出 mode。其他情况返回假。| |unalias [-a] [name …]|从已定义的别名列表中删除 name。如果给出了 -a将删除所有别名定义。返回值是真,除非给出的 name不是已定义的别名。| |unset [-fv] [name …]|将每个 name对应的变量或函数删除。如果没有给出选项,或者给出了 -v选项, name仅包括 shell 变量。只读的变量不能被取消定义。如果给出了 -f选项, name仅包括 shell 函数,函数的定义将被删除。每个被取消定义的变量或函数都被从后续命令的环境中删除。如果 RANDOM , SECONDS , LINENO , HISTCMD , FUNCNAME , GROUPS ,或者 DIRSTACK中的任何一个被取消定义,它们将丧失特殊的属性,即使它们后来被重新定义。退出状态是真,除非 name不存在或是只读的。| |wait [n]`|等待指定的进程,返回它的终止状态。 n可以是进程 ID 或一个作业号;如果给出的是作业号,将等待作业的管道中所有进程。如果没有给出 n,将等待所有当前处于激活状态的子进程,返回状态是 0。如果 n指定了不存在的进程或作业,返回状态是 127。否则,返回状态是所等待的最后一个进程或作业的退出状态。|

另有caller、compopt、coproc、mapfile、readarray等。

bash 可执行文件

文件 用途
/etc/profile 系统范围的初始化文件,登录 shell 会执行它
~/.bash_profile 个人初始化文件,登录 shell 会执行它
~/.bashrc 个人的每个交互式 shell 启动时执行的文件
~/.bash_logout 个人的登录 shell 清理文件,当一个登录 shell 退出时会执行它
~/.inputrc 个人的 readline 初始化文件

总结

Bash作为shell语言的中流砥柱,充分体现了shell的精神,拥有大量方便的特性,同时也就只专于此。它为了一些用法提供紧凑的表示,不惜以ad-hoc的语法和语义为代价。Shell重度基于文本而没有像样的类型系统,作用域不健壮。于是,当稍为离开shell领域,其脆弱性就显得突出。这也许正是Shell总是与各种小语言(awk、sed、troff……)结伴前行的原因,难道这就是所谓的做一件事并做好?这能叫KISS吗?