











本译文基于《The GNU Bash Reference Manual》(Edition 5.3,2025 年 5 月 18 日更新,适用于 Bash 5.3 版),由英文原版全文翻译、整理而成。
翻译约定
- 术语首次出现时附英文原名(如「内建命令(builtin)」「退出状态(exit status)」),之后统一使用中文译名;专有名词(GNU、POSIX、Readline、Emacs、vi 等)保留英文。
- 文中的「译者注」为翻译时补充的中文注释与可运行示例,用于解释难懂或易混淆之处;示例均经 Bash 实测验证。
- 原文的笔误、语法与逻辑问题已在译文中修正,修正明细汇总于文末「校对与修正记录」。
- 附录 C(GNU 自由文档许可证)为官方许可证文本,按原文保留英文;附录 D 索引条目为英文关键字,保留原文以便检索。
- 原文的交叉引用在译文中保留节号并给出标准译名,如「参见第 3.6 节(重定向)」。
$"...")set 内建命令shopt 内建命令本手册简要描述 Bash Shell(版本 5.3,2025 年 5 月 18 日)所具备的功能。Bash 主页为 http://www.gnu.org/software/bash/。
本文档为《GNU Bash 参考手册》第 5.3 版,最近更新于 2025 年 5 月 18 日,适用于 Bash 5.3 版。
Bash 含有其他流行 Shell 中的功能,也有一些仅 Bash 才有的功能。Bash 借鉴过概念的 Shell 有 Bourne Shell(sh)、Korn Shell(ksh)和 C-shell(csh 及其后继者 tcsh)。下面的目录把各功能分门别类,并注明哪些功能受其他 Shell 启发、哪些是 Bash 特有的。
译者注:这里的「目录」指的就是本手册顶部的目录列表。在 Texinfo 源文档中它称为 menu(菜单),TeXinfo 生成器会把它排版为书本的目录(TOC)——所以原文说「following menu」时,指的就是全书目录。
本手册旨在作为 Bash 功能的简要介绍。有关 Shell 行为的权威参考,应以 Bash 手册页(manual page)为准。
Bash 是 GNU 操作系统的 Shell,即命令语言解释器(command language interpreter)。名称是「Bourne-Again SHell」的缩写,是对 Stephen Bourne 的戏仿。Stephen Bourne 是当今 Unix Shell「sh」直接前身的作者,该 Shell 出现在贝尔实验室研究部门(Bell Labs Research)的第七版 Unix 中。
译者注:「Bourne-Again」读起来与「born again」(重生)谐音,所以 Bash 这个名称的含义是「重生的 sh」,借此向 sh 的作者 Stephen Bourne 致敬。类似地,GNU 这个名称是「GNU's Not Unix」的递归缩写,也是软件圈常见的命名趣味。
Bash 与 sh 高度兼容,并吸收了 Korn Shell(ksh)和 C Shell(csh)的有用功能。它旨在成为符合 IEEE POSIX 规范(IEEE 标准 1003.1)中 Shell 与工具(Shell and Tools)部分的实现。无论用于交互还是编程,它都比 sh 提供了功能上的改进。
译者注:POSIX 是「Portable Operating System Interface(可移植操作系统接口)」的缩写,是一族基于 Unix 的开放系统标准。用
bash --posix启动,或在交互式 Bash 中执行set -o posix,即可让 Bash 进入 POSIX 模式。本手册第 6.11 节(Bash 与 POSIX)会详细介绍。
虽然 GNU 操作系统还提供其他 Shell(包括一个 csh 版本),Bash 是默认 Shell。与其他 GNU 软件一样,Bash 的移植性相当好。它目前几乎运行于每个版本的 Unix 和一些其他操作系统上——Windows 及其他平台另有独立支持的移植版本。
从根本上说,Shell 只是一个执行命令的宏处理器(macro processor)。所谓宏处理器,是指把文本和符号展开以生成更大表达式的功能。
译者注:Shell 里的「展开」无处不在:变量引用
$name会展开成变量的值,*.txt会展开成匹配的文件名,{a,b}会展开成a b。Shell 先完成这些展开,然后才真正执行命令。例如:# 译者注示例:命令执行前的文本展开 $ name=world $ echo "hello $name" hello world
一个 Unix Shell 既是命令解释器,也是一种编程语言。作为命令解释器,Shell 为用户提供了与丰富的 GNU 实用工具集交互的界面。编程语言特性则允许把这些实用工具组合起来。用户可以创建包含命令的文件,而这些文件本身又成为命令。这些新命令与 /bin 等目录中的系统命令地位相同,让用户或用户组能够建立自定义环境,自动完成常见任务。
Shell 可以交互式或非交互式使用。在交互模式下,Shell 接受从键盘输入的内容;非交互式执行时,Shell 执行从文件或字符串中读取的命令。
译者注:典型的非交互式用法有两种:把一段命令字符串传给
bash -c,或者直接运行一个脚本文件。这两种方式下都没有键盘输入,也不显示提示符。例如:# 译者注示例:非交互式执行一段字符串命令 $ bash -c 'echo hello from non-interactive bash' hello from non-interactive bash
Shell 允许同步或异步执行 GNU 命令。同步命令执行完成后,Shell 才会接受更多输入;异步命令则与 Shell 并行继续执行,与此同时 Shell 还在读取并执行后续命令。「重定向」(redirection)结构允许对命令的输入和输出进行细粒度控制。此外,Shell 还允许控制命令所拥有环境(environment)的内容。
译者注:把命令放在
&之后即为异步(后台)执行,Shell 不会等待它,提示符立即返回。例如:# 译者注示例:异步执行 —— sleep 在后台运行,提示符立即返回 $ sleep 5 & [1] 27182 $之后可用
fg把后台作业带回前台,或用wait等待它结束。详见第 7 章(作业控制)。
Shell 还提供一小组内建命令(builtin),用于实现无法或不方便通过独立实用工具获得的功能。例如,cd、break、continue 和 exec 无法在 Shell 之外实现,因为它们直接操纵 Shell 本身。history、getopts、kill、pwd 等内建命令虽然也可以用独立实用工具实现,但作为内建命令使用更为方便。所有 Shell 内建命令都将在后续章节中描述。
译者注:为什么 cd 必须是内建命令?cd 要改变的是「当前 Shell 进程」自己的工作目录,而任何外部程序都只能改变自己进程的目录,退出后即失效,不可能影响父进程的 Shell。exec 要用新程序替换当前 Shell 进程,同样只能由 Shell 自己完成。例如:
# 译者注示例:子 Shell 中 cd 只影响子 Shell,退出后当前目录不变 $ (cd /etc; pwd) /etc $ pwd /home/you
尽管执行命令是根本,Shell 的大部分威力(和复杂性)却来自其内嵌的编程语言。与任何高级语言一样,Shell 提供变量、流程控制结构、引号机制(quoting)和函数。
Shell 提供的功能中,有一部分专门针对交互式使用,而不是为了扩充编程语言。这些交互功能包括作业控制(job control)、命令行编辑(command line editing)、命令历史(history)和别名(alias)。本手册将描述 Bash 如何提供所有这些功能。
以下定义将贯穿使用于本手册其余部分。
POSIX
一族基于 Unix 的开放系统标准。Bash 主要关注 POSIX 1003.1 标准中的 Shell 与实用工具(Shell and Utilities)部分。
空格(blank)
空格或制表符。
空白字符(whitespace)
属于当前区域设置(locale)中 space 字符类别、或使 isspace() 返回真的字符。
译者注:blank 与 whitespace 并不等同:blank 严格指空格和制表符两种字符;whitespace 依区域设置而定,范围可能更大。二者在分词(word splitting,见第 3.5.7 节)时都用于分隔单词。例如某些区域设置下
isspace()对换行符也返回真。
内建命令(builtin)
由 Shell 自身在内部实现、而不是由文件系统中某个可执行程序实现的命令。
控制操作符(control operator)
执行控制功能的记号(token)。它指换行符或下列字符之一:||、&&、&、;、;;、;&、;;&、|、|&、(、)。
译者注:
||与&&分别是「或」与「且」的逻辑连接;;;、;&、;;&三种都用于 case 语句;|&是2>&1 |的简写,把标准错误也接入管道。例如;;&会像 C 语言那样继续测试后续分支:# 译者注示例:case 中 ;; 终止分支,;;& 继续测试后续分支 $ v=foo; case $v in foo) echo A ;;& *) echo B;; esac A B
退出状态(exit status)
命令返回给其调用者的值。该值被限制为八个二进制位,因此最大值为 255。
译者注:Shell 约定 0 表示成功,非 0 表示失败;上一命令的退出状态存放在特殊参数
$?中。状态值超过 255 时会按 256 取模,例如:# 译者注示例:退出状态超出 0–255 时取模 $ bash -c 'exit 300'; echo $? 44
字段(field)
作为某次 Shell 展开的结果而产生的文本单位。展开之后,在执行命令时,产生的字段被用作命令名和参数。
文件名(filename)
用来标识一个文件的字符串。
作业(job)
构成一个管道的一组进程,以及由它们派生的所有进程,这些进程全都处于同一个进程组中。
译者注:作业(job)是用户视角的概念:在交互式 Shell 中,
sleep 30 | sleep 30这样用管道连起来的一串命令算一个作业,可以整体挂起、恢复或终止。进程组(process group)则是内核层面的实现机制——同一管道中的进程被放进同一个进程组,以便整体接收信号。两者的关系在第 7 章(作业控制)会详细说明。
作业控制(job control)
用户可以按需停止(挂起)和重新启动(恢复)进程执行的机制。
译者注:前台运行耗时命令时按 Ctrl-Z 即可挂起它,再用
bg放到后台继续运行、用fg带回前台:# 译者注示例:挂起前台作业后转入后台 $ sleep 60 ^Z [1]+ Stopped sleep 60 $ bg [1]+ sleep 60 &
元字符(metacharacter)
未加引号时能分隔单词的字符。元字符是空格、制表符、换行符,或下列字符之一:|、&、;、(、)、<、>。
译者注:同一个字符,未加引号时是元字符、起分隔作用,加引号后就只是普通字符:
# 译者注示例:未加引号的 ; 是元字符,两条命令依次执行 $ echo a; echo b a b $ echo 'a;b' a;b
名称(name)
仅由字母、数字和下划线组成、且以字母或下划线开头的单词(word)。名称用作 Shell 变量名和函数名,也称为标识符(identifier)。
译者注:变量名必须遵守此规则:
1var=x不会被当作赋值(名称不能以数字开头),my-var=x也无效(连字符不属于名称字符),它们都会被当作命令名去查找而报错。合法的例子如_tmp=1、MY_VAR=2。
操作符(operator)
控制操作符或重定向操作符。重定向操作符的列表参见第 3.6 节(重定向)。操作符至少包含一个未加引号的元字符。
译者注:操作符可以由多个元字符组合而成,例如
>>(追加重定向)、2>&1(把文件描述符 2 复制到文件描述符 1)、<<(here-document,此处文档)。这些操作符的详细说明见第 3.6 节(重定向)。
进程组(process group)
具有相同进程组 ID 的一组相关进程。
译者注:管道是把进程放进同一进程组的最常见方式。可用
ps -o pid,pgid,cmd查看进程组 ID:同一管道中的各进程 pgid 相同,且等于组首进程的 PID。
进程组 ID(process group ID)
在进程组存续期间唯一标识该进程组的标识符。
保留字(reserved word)
对 Shell 具有特殊含义的单词(word)。多数保留字用于引出 Shell 的流程控制结构,例如 for 和 while。
译者注:保留字是语法的一部分,不能用作变量名或命令名;内建命令则只是由 Shell 内部实现的命令,仍可像普通命令一样使用:
# 译者注示例:if 是保留字,echo 是内建命令 $ if=1 bash: syntax error near unexpected token `=1' $ echo=1; echo "$echo" 1
返回状态(return status)
退出状态的同义词。
信号(signal)
内核用来通知进程系统中有事件发生的机制。
译者注:按下 Ctrl-C 会向前台进程发送 SIGINT 信号,Ctrl-Z 发送 SIGTSTP。
kill -l可列出全部信号名;kill -TERM 1234可向指定进程发送信号。Shell 脚本可用内建命令 trap 捕获信号并执行自定义处理。
特殊内建命令(special builtin)
被 POSIX 标准归类为特殊的内建命令。
译者注:POSIX 规定的特殊内建命令包括 break、
:、continue、.、eval、exec、exit、export、readonly、return、set、shift、times、trap、unset。它们与普通内建命令的差别在于:在 POSIX 模式下,特殊内建命令出错会导致非交互式 Shell 退出,且执行前不做命令查找。第 4.4 节(特殊内建命令)会详细介绍。
记号(token)
Shell 视为一个整体的字符序列。它要么是单词(word),要么是操作符(operator)。
译者注:token、word、field 是三个容易混淆的概念:token 是 Shell 分词(lexical)阶段切分输入得到的最小单位(非 word 即 operator);field 是展开(expansion)阶段之后的结果。一个单词展开后可能拆成多个字段(单词拆分),例如未加引号的
$x:# 译者注示例:一个单词展开后产生两个字段 $ x="a b" $ printf '<%s>\n' $x # $x 未加引号,按空白拆成两个字段 <a> <b> $ printf '<%s>\n' "$x" # 加引号则整体算一个字段 <a b>
单词(word)
Shell 视为一个整体的字符序列。单词不得包含未加引号的元字符。
译者注:反过来说,一旦把元字符用引号括起来,它就只是单词的一部分。例如
foo;bar会被拆成「单词 foo、操作符 ;、单词 bar」三个部分,而'foo;bar'是单个单词。引号机制的详细规则见第 3.1.2 节(引号机制)。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。