深入理解BashShell重定向
简介
Linux 终端下的重定向功能在日常办公中经常被使用到,深入理解并熟练掌握 Bash Shell 的重定向将有助于提升办公效率。Bash Shell 下的重定向是通过文件描述符实现的,Linux 系统默认有三个标准的文件描述符:
stdin
:标准输入,文件描述符0
。stdout
:标准输出,文件描述符1
。stderr
:标准错误,文件描述符2
。
假设 Linux 终端设备为 /dev/tty0
,则 Linux 系统下标准文件描述符在 Bash Shell 中与设备的映射关系如下:
一种简单好理解重定向符的方法:将
>/<
看做是赋值语句中的=
,前者的方向代表后者的赋值方向;将&
看做是$
。
重定向标准输出到文件
1 | command >file |
其中,>
操作符是输出重定向操作符。Bash 首先会尝试打开 file
文件,如果成功打开则将 command
的标准输出发送到 file
文件中,并将原来的内容覆盖;如果无法打开,则该条命令执行失败并报错。
command >file
等价于 command 1>file
,这是因为 1
是输出重定向默认的文件描述符。该命令下,文件描述表与设备的映射关系如下:
重定向到文件的一般命令为 command n>file
,其中 n
为需要重定向的文件描述符。
为了避免不小心覆盖已有文件,可以为当前 Shell 设置 noclobber
选项:
1 | set -o noclobber |
这样之后,如果 file
已经存在,>file
就是报错。在这种情况下,如果你确定一定要覆盖,可以使用 >|
操作符。
1 | command >| file |
重定向标准错误到文件
1 | command 2>file |
该命令下,文件描述符表与设备的映射关系如下:
定向标准输出和标准错误到文件
1 | command &>file |
其中,&>
操作符用来同时重定向 stdout
和 stderr
。该命令下,文件描述符表与设备的映射关系如下:
重定向的先后顺序
一种等价于 &>
操作的重定向命令为:
1 | command >file 2>&1 |
其中,先后出现了两次重定向:
- 第一次是将
stdout
重定向到file
; - 第二次是将
stderr
重定向到文件描述符1
,而1
已经被重定向到file
,所以等价于stderr
重定向到file
。
该命令下,文件描述符表与设备的映射关系如下:
与之不同的是,如果将 2>&1
提前到 >file
,则对应的含义完全不同:
1 | command 2>&1 >file |
其中,先后出现了两次重定向:
- 第一次是将
stderr
重定向到stdout
,此时stdout
映射到终端/dev/tty0
,故等价于stderr
重定向到/dev/tty0
; - 第二次是将
stdout
重定向到file
。
该命令下,文件描述符表与设备的映射关系如下:
丢弃标准输出
1 | command > /dev/null |
/dev/null
是 Linux 系统中特殊的虚拟设备,其会将发送给它的所有内容丢弃。
重定向标准输入
1 | command <file |
其中,<
操作符是输入重定向操作符。Bash 首先会尝试打开 file
文件,如果成功打开则 file
中的内容重定向到 command
作为输入;如果无法打开,则该条命令执行失败并报错。
该命令下,文件描述符表与设备的映射关系如下:
重定向多条文本到标准输入
1 | command <<EOF |
其中,<<MARKER
操作符用来重定向文本内容。该命令会将两个 MARKER
中包裹的文件内容重定向到标准输入。
重定向单行文件到标准输入
1 | command <<< "foo bar baz" |
该命令等价于:
1 | echo "foo bar baz" | command |
固定重定向标准错误到文件
1 | exec 2>file |
exec
是 Linux Bash 内建命令,该命令会将 stderr
固定重定向到 file
文件,直到再次修改重定向或退出当前的 Bash Shell。
固定输入重定向文件描述符
1 | exec 3<file |
该命令会尝试打开 file
文件,并分配文件描述符 3
指定到 file
,用于后续输入需要。比如:
1 | grep "foo" <&3 |
如果想要关掉文件描述符 3
,则可以使用以用命令:
1 | exec 3>&- |
固定输出重定向文件描述符
1 | exec 4>file |
与输入重定向文件描述符一样,如果想要关掉文件描述符 4
,可以使用以下命令:
1 | exec 4>&- |
固定输入输出重定向文件描述符
1 | exec 3<>file |
合并多输出重定向到文件
1 | (command1; command2) >file |
重定向到文件和终端
1 | command | tee file |
tee
命令常用来将输出重定向到文件,同时又保留终端输出。其工作方式如下:
管道通信
Bash Shell 下的管道 |
可以用来在不同命令间通信,比如:
1 | command1 | command2 |
该命令会将 command1
的标准输出和 command2
的标准输入连接,其对应的输入输出映射关系如下:
如果需要将 command1
的标准错误也发送给 command2
,可以使用 |&
操作符:
1 | command1 |& command2 |
或者先将 command1
的标准错误重定向到其标准输出,即等价于以下命令:
1 | command1 2>&1 | command2 |
交换标准输出和标准错误
1 | command 3>&1 1>&2 2>&3 |
分别重定向标准输出和标准错误
1 | command > >(stdout_cmd) 2> >(stderr_cmd) |
其中,>(...)
操作符会将 ...
的 stdin
连接到一个匿名管道,这里即对应 command
的 stdout
,再执行 ...
。