ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

GNU Bash 参考手册(中文版)(一)

GNU Bash 参考手册(中文版)(一)

GNU Bash 参考手册(中文版)

本译文基于《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 节(重定向)」。

Bash 功能(手册导言)

  • Bash 功能(手册导言)
  • 1 简介
    • 1.1 什么是 Bash?
    • 1.2 什么是 Shell?
  • 2 定义
  • 3 基本 Shell 功能
    • 3.1 Shell 语法
      • 3.1.1 Shell 的运行过程
      • 3.1.2 引号机制
        • 3.1.2.1 转义字符
        • 3.1.2.2 单引号
        • 3.1.2.3 双引号
        • 3.1.2.4 ANSI-C 引号
        • 3.1.2.5 区域设置相关的翻译($"..."
      • 3.1.3 注释
    • 3.2 Shell 命令
      • 3.2.1 保留字
      • 3.2.2 简单命令
      • 3.2.3 管道
      • 3.2.4 命令列表
      • 3.2.5 复合命令
        • 3.2.5.1 循环结构
        • 3.2.5.2 条件结构
        • 3.2.5.3 组合命令
      • 3.2.6 协程
      • 3.2.7 GNU Parallel(保持英文)
    • 3.3 Shell 函数
    • 3.4 Shell 参数
      • 3.4.1 位置参数
      • 3.4.2 特殊参数
    • 3.5 Shell 展开
      • 3.5.1 花括号展开
      • 3.5.2 波浪号展开
      • 3.5.3 Shell 参数展开
      • 3.5.4 命令替换
      • 3.5.5 算术展开
      • 3.5.6 进程替换
      • 3.5.7 单词拆分
      • 3.5.8 文件名展开
        • 3.5.8.1 模式匹配
      • 3.5.9 引号去除
    • 3.6 重定向
      • 3.6.1 重定向输入
      • 3.6.2 重定向输出
      • 3.6.3 追加重定向输出
      • 3.6.4 重定向标准输出与标准错误
      • 3.6.5 追加标准输出与标准错误
      • 3.6.6 Here-Documents(此处文档)
      • 3.6.7 Here-Strings(此处字符串)
      • 3.6.8 复制文件描述符
      • 3.6.9 移动文件描述符
      • 3.6.10 以读写方式打开文件描述符
    • 3.7 命令执行
      • 3.7.1 简单命令的展开
      • 3.7.2 命令的查找与执行
      • 3.7.3 命令执行环境
      • 3.7.4 环境
      • 3.7.5 退出状态
      • 3.7.6 信号
    • 3.8 Shell 脚本
  • 4 Shell 内建命令
    • 4.1 Bourne Shell 内建命令
    • 4.2 Bash 内建命令
    • 4.3 修改 Shell 行为
      • 4.3.1 set 内建命令
      • 4.3.2 shopt 内建命令
    • 4.4 特殊内建命令
  • 5 Shell 变量
    • 5.1 Bourne Shell 变量
    • 5.2 Bash 变量
  • 6 Bash 功能
    • 6.1 调用 Bash
    • 6.2 Bash 启动文件
    • 6.3 交互式 Shell
      • 6.3.1 什么是交互式 Shell?
      • 6.3.2 当前 Shell 是否交互?
      • 6.3.3 交互式 Shell 的行为
    • 6.4 Bash 条件表达式
    • 6.5 Shell 算术
    • 6.6 别名
    • 6.7 数组
    • 6.8 目录栈
      • 6.8.1 目录栈内建命令
    • 6.9 控制提示符
    • 6.10 受限 Shell
    • 6.11 Bash 与 POSIX
      • 6.11.1 什么是 POSIX?
      • 6.11.2 Bash 的 POSIX 模式
    • 6.12 Shell 兼容模式
  • 7 作业控制
    • 7.1 作业控制基础
    • 7.2 作业控制内建命令
    • 7.3 作业控制变量
  • 8 命令行编辑
    • 8.1 行编辑简介
    • 8.2 与 Readline 交互
      • 8.2.1 Readline 基本要点
      • 8.2.2 Readline 移动命令
      • 8.2.3 Readline 删除(killing)命令
      • 8.2.4 Readline 参数
      • 8.2.5 在历史中搜索命令
    • 8.3 Readline 初始化文件
      • 8.3.1 Readline 初始化文件语法
      • 8.3.2 条件初始化结构
      • 8.3.3 初始化文件示例
    • 8.4 可绑定的 Readline 命令
      • 8.4.1 移动命令
      • 8.4.2 操作历史记录的命令
      • 8.4.3 修改文本的命令
      • 8.4.4 删除(Killing)与粘贴(Yanking)
      • 8.4.5 指定数值参数
      • 8.4.6 让 Readline 替你输入
      • 8.4.7 键盘宏
      • 8.4.8 其他命令
    • 8.5 Readline 的 vi 模式
    • 8.6 可编程补全
    • 8.7 可编程补全内建命令
    • 8.8 可编程补全示例
  • 9 交互式使用历史记录
    • 9.1 Bash 的历史记录设施
    • 9.2 Bash 历史记录内建命令
    • 9.3 历史展开
      • 9.3.1 事件指示符
      • 9.3.2 单词指示符
      • 9.3.3 修饰符
  • 10 安装 Bash
    • 10.1 基本安装
    • 10.2 编译器与选项
    • 10.3 为多种架构编译
    • 10.4 安装名称
    • 10.5 指定系统类型
    • 10.6 共享默认配置
    • 10.7 操作控制
    • 10.8 可选功能
  • 附录 A 报告缺陷
  • 附录 B 与 Bourne Shell 的主要差异
    • B.1 与 SVR4.2 Shell 的实现差异
  • 附录 C GNU 自由文档许可证(原文保留英文)
  • 附录 D 索引(条目保留英文)
    • D.1 Index of Shell Builtin Commands
    • D.2 Index of Shell Reserved Words
    • D.3 Parameter and Variable Index
    • D.4 Function Index
    • D.5 Concept Index

本手册简要描述 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)为准。

1 简介

1.1 什么是 Bash?

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 及其他平台另有独立支持的移植版本。

1.2 什么是 Shell?

从根本上说,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 如何提供所有这些功能。

2 定义

以下定义将贯穿使用于本手册其余部分。

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=1MY_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 节(引号机制)。

返回列表