声明:本文梳理自 GNU Bash 参考手册:https://www.gnu.org/software/bash/manual/bash.html;部分借鉴自通义千问 AI。
3.6 重定向(Redirections)
在执行命令之前,可以使用 shell 解释的特殊符号将其输入和输出进行重定向(redirection)。重定向允许命令的文件描述符被复制、打开、关闭,或者指向不同的文件,并且能够改变命令读取和写入的文件。重定向也可以用来修改当前 shell 执行环境中的文件描述符。下面列出的重定向操作符可以在简单命令之前、之中或之后出现。重定向按照从左到右的顺序处理。
每个可以由文件描述符号码前导的重定向,也可以由形如 {varname}
的词前导。在这种情况下,除了 >&-
和 <&-
之外的每个重定向操作符,shell 都会分配一个大于 10 的文件描述符并将其赋值给 {varname}
。如果 >&-
或 <&-
被 {varname}
前导,则 varname
的值定义了要关闭的文件描述符。如果提供了 {varname}
,则重定向将持续超过命令的作用域,允许 shell 程序员手动管理文件描述符的生命周期。varredir_close
shell 选项管理此行为(详见 “4.3.2 内置 Shopt 命令”)。
在以下描述中,如果省略了文件描述符号码:
- 如果重定向操作符的第一个字符是
<
,则该重定向指的是标准输入(文件描述符0
) - 如果重定向操作符的第一个字符是
>
,则该重定向指的是标准输出(文件描述符1
)
在以下描述中,重定向操作符后面跟随的词,除非另有说明,将经历括号展开、波浪线展开、参数展开、命令替换、算术展开、引号移除、文件名展开以及单词分割。如果它展开了多于一个词,Bash 将报告错误。
需要注意的是,重定向的顺序是很重要的。例如:
ls > dirlist 2>&1
将标准输出(文件描述符 1
)和标准错误(文件描述符 2
)都导向文件 dirlist
,而命令
ls 2>&1 > dirlist
只将标准输出导向文件 dirlist
,因为标准错误在标准输出被重定向到 dirlist
之前已经被设置为标准输出的一个副本。
Bash 在重定向中使用几个特殊文件名时会进行特殊处理,如下表所述。如果运行 Bash 的操作系统提供了这些特殊文件,Bash 将使用它们;否则,它将在内部模拟这些文件,并表现出以下描述的行为。
/dev/fd/fd
:如果 fd 是一个有效的整数,则复制文件描述符 fd。/dev/stdin
:复制文件描述符 0。/dev/stdout
:复制文件描述符 1。/dev/stderr
:复制文件描述符 2。/dev/tcp/host/port
:如果 host 是一个有效的主机名或互联网地址,并且 port 是一个整数端口号或服务名称,Bash 会尝试打开相应的 TCP socket/dev/udp/host/port
:如果 host 是一个有效的主机名或互联网地址,并且 port 是一个整数端口号或服务名称,Bash 会尝试打开相应的 UDP socket。
打开或创建文件失败会导致重定向失败。
使用大于 9 的文件描述符进行重定向时应谨慎,因为它们可能会与 shell 内部使用的文件描述符产生冲突。
3.6.1 重定向输入(Redirected Input)
输入(input)重定向会导致由单词扩展得到的文件名所对应的文件以读取模式打开,并且该文件被关联到文件描述符 n
上;如果没有指定 n
,则默认使用标准输入(文件描述符 0)。
输入重定向的一般格式为:
[n]<word
其中的
[n]
是可选的文件描述符编号,如果省略,则默认为 0(即标准输入);word
代表要打开的文件名,它可能会经过 shell 的扩展处理。例如,将data.txt
文件作为命令的标准输入:command < data.txt
3.6.2 重定向输出(Redirected Output)
输出(output)重定向会导致由 word
展得到的文件名所对应的文件以写入模式打开,并且该文件被关联到文件描述符 n
上;如果没有指定 n
,则默认使用标准输出(文件描述符 1)。如果文件不存在,则会创建该文件;如果文件已经存在,则它会被截断至零大小(即清空文件内容)。
输出重定向的一般格式为:
[n]>[|]word
- 如果重定向操作符是
>
,并且内置命令set
的noclobber
选项已被启用,那么当由word
扩展得到的文件名对应的文件存在且是一个普通文件时,重定向将会失败。 - 如果重定向操作符是
>|
,或者重定向操作符是>
而noclobber
选项未被启用,即使由word
指定的文件已存在,重定向也会尝试执行。
3.6.3 追加重定向输出(Appending Redirected Output)
重定向输出以这种方式会导致由单词扩展得到的文件名被打开用于在文件描述符 n 上追加内容,如果未指定 n,则默认为标准输出(文件描述符 1)。如果文件不存在,则会创建该文件。
追加输出的一般格式是:
[n]>>word
3.6.4 重定向标准输出和标准错误输出(Redirecting Standard Output and Standard Error)
这种结构允许将标准输出(文件描述符1)和标准错误输出(文件描述符2)都重定向到由单词扩展得到的文件名所指定的文件中。
对于重定向标准输出和标准错误,有两种格式:
&>word
和
>&word
在这两种形式中,推荐使用第一种。这在语义上等同于
>word 2>&1
当使用第二种形式时,word
不能扩展为一个数字或 -
。如果它确实扩展成了这些值,那么为了兼容性原因,会应用其他重定向操作符。(详见下文 “Duplicating File Descriptors”)
3.6.5 追加重定向标准输出和标准错误输出(Appending Standard Output and Standard Error)
这种结构允许将标准输出(文件描述符1)和标准错误输出(文件描述符2)都追加到由单词扩展得到的文件名所指定的文件中。
追加标准输出和标准错误的格式是:
&>>word
这在语义上等同于
>>word 2>&1
(详见下文 “Duplicating File Descriptors”)
3.6.6 Here Documents
这种类型的重定向告诉 shell 从当前源读取输入,直到遇到一行只包含 word
(没有尾随空格)为止。到那时为止读取的所有行都将用作命令的标准输入(如果指定了 n
,则作为文件描述符 n
)。
Here Document 的格式是:
[n]<<[-]word
here-document
delimiter
在 word
上不会执行任何参数和变量扩展、命令替换、算术扩展或文件名扩展。如果 word 的任何部分被引号包围,那么 delimiter
就是对 word
进行引号移除后的结果,并且 here document 中的行不会被扩展。如果 word
没有被引号包围,here document 中的所有行都会经过参数扩展、命令替换和算术扩展处理,字符 \n
会被忽略,并且必须使用 \
来转义字符 \
、$
和 `。
如果重定向操作符是 <<-
,那么会从输入行和包含 delimiter
的行中删除所有的前导制表符。这允许 shell 脚本中的 here document 以自然的方式缩进。
3.6.7 Here Strings
这是一种 here document 的变体,其格式为:
[n]<<< word
这里的 word
会经历波浪线展开、参数和变量展开、命令替换、算术展开以及引号移除。但不会进行文件名扩展和单词拆分。最终的结果作为一个单独的字符串,并在末尾追加一个换行符,提供给命令的标准输入(如果指定了 n
,则是文件描述符 n
)。
3.6.8 复制文件描述符
重定向操作符:
[n]<&word
用于复制输入文件描述符。如果 word
展开为一个或多个数字,那么由 n
表示的文件描述符将被设置为该文件描述符的一个副本。如果 word
中的数字没有指定一个打开的输入文件描述符,则会发生重定向错误。如果 word
的值为 -
,则关闭文件描述符 n
。如果没有指定 n
,则使用标准输入(文件描述符0)。
类似的,重定向操作符:
[n]>&word
用于复制输出文件描述符。如果没有指定 n
,则使用标准输出(文件描述符1)。如果 word
中的数字没有指定一个打开的输出文件描述符,则会发生重定向错误。如果 word
的值为 -
,则关闭文件描述符 n
。作为特殊情况,如果省略了 n
并且 word
不展开为一个或多个数字或 -
,则标准输出和标准错误将按前面所述的方式被重定向。
3.6.9 移动文件描述符
重定向操作符:
[n]<&digit-
将文件描述符 digit
移动到文件描述符 n
,如果未指定 n
,则移动到标准输入(文件描述符 0)。在被复制到 n
后,digit
将被关闭。
类似地,重定向操作符:
[n]>&digit-
将文件描述符 digit
移动到文件描述符 n
,如果未指定 n
,则移动到标准输出(文件描述符 1)。在被复制到 n
后,digit
也将被关闭。
3.6.10 打开文件描述符以进行读写
重定向操作符:
[n]<>word
会导致名称为 word
展开后所指的文件在文件描述符 n
上被打开,以便同时进行读取和写入操作;如果没有指定 n
,则会在文件描述符 0 上进行。如果该文件不存在,则会被创建。