首先,除了一些例外,重定向通常发生在它们被写入的地方。它们从命令和参数序列中删除;只有剩余的、非重定向的单词参与。因此:
3>&1 foo 1>&2 arg1 2>&3 arg2 3>&- arg3
交换 stdout 和 stderr运行foo arg1 arg2 arg3
,因为:
3>&1
dup2
在 fd 3 上制作 fd 1 (stdout)的副本(更准确地说是 a )
1>&2
在 fd 1 上复制 fd 2 (stderr) (所以现在 stdout 和 stderr 都去他们要去的任何地方)
2>&3
在 fd 2 (stderr) 上复制 fd 3 (保存的原始标准输出)
3>&-
关闭 fd 3。
(值得注意的例外是管道输出“首先发生”,即使管道符号位于简单命令部分的末尾。)
其次,正如 pje 所指出的,time
它是内置的 bash。 time foo
运行命令,然后将时间摘要打印到 bash 的标准错误。首先time
有效地删除关键字,然后照常处理剩余的命令序列。(即使命令是管道,这也适用:time
乘以整个管道。)
在这种情况下,命令序列是一个简单的命令,带有重定向:
2>&1 sh 2>&1 -c ... > file
每个重定向都发生在它被写入的地方,剩下的顺序是:
sh -c ...
重定向是:
- 将 stderr 发送到 stdout 当前所在的任何位置
- 再次将标准错误发送到标准输出(这没有新效果)
- 将标准输出发送到
file
.
所以sh -c
运行它的 stderr 去你的 stdout,它的 stdout 去 file file
。如您所述,dd
将其输出打印到(其)stderr,即sh -c ...
'stderr,即您的标准输出。
如果你运行:
time 2>file dd if=/dev/zero of=ddfile bs=512 count=125
您将time
在 stderr(例如屏幕)上获得 'stderr 输出,并dd
在文件中获得 'stderr file
。(无论您将2>file
部件向右滑动多远,只要它仍然是简单命令的一部分,都会发生这种情况。)
如果你试试:
2>file time ...
你会发现time
's 的输出被重定向,但这完全破坏了内置的time
,而是运行/usr/bin/time
。要让 bash 的内置程序启动,time
必须提前。您可以制作一个子外壳:
(time ...) 2>file
或pje 所示的子块:
{ time ...; } 2>file
(子块的语法比较笨拙,因为需要空格和/或分号,但它避免了fork
系统调用)。