我有这个:
$ time 2>&1 sh 2>&1 -c "dd if=/dev/zero of=ddfile bs=512 count=125 && sync" > file
中的125 + 0记录
125 + 0记录
复制<64> 64000字节(64 kB),0.000617678 s,104 MB / s真实的0m0.133s
用户0m0.000s
sys 0m0.020s
$ cat file
文件为空。
问题:我理解dd
和time
都将他们的o / p发送给stderr。但是因为我将stderr重定向到stdout for time
和sh
(这是dd
的父进程)并且还发送了stdout来转到文件我希望将事情写入文件。为什么没有发生?
答案 0 :(得分:4)
如果要重定向time
及其子命令的输出,可以将它们分组为代码块并将其stderr重定向到该文件:
$ { time sh -c "dd if=/dev/zero of=ddfile bs=512 count=125 && sync"; } 2> file
......产生:
$ cat file
125+0 records in
125+0 records out
64000 bytes (64 kB) copied, 0.000617678 s, 104 MB/s
real 0m0.133s
user 0m0.000s
sys 0m0.020s
答案 1 :(得分:3)
首先,除了一些例外,重定向通常发生在它们被写入的位置。它们从命令和参数序列中删除;只有剩下的,非重定向,单词参与。因此:
3>&1 foo 1>&2 arg1 2>&3 arg2 3>&- arg3
与stdout和stderr交换运行foo arg1 arg2 arg3
,因为:
3>&1
在fd 3上制作了fd 1(stdout)的副本(更确切地说,是dup2
)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的stderr。首先有效删除time
关键字,然后照常处理剩余的命令序列。 (即使命令是管道,这也适用:time
乘以整个管道。)
在这种情况下,命令序列是一个简单的命令,带有重定向:
2>&1 sh 2>&1 -c ... > file
每次重定向都发生在它写入的位置,剩下的序列是:
sh -c ...
重定向是:
file
。所以sh -c
运行时它的stderr会转到你的stdout,而它的stdout会转到文件file
。正如您所注意到的,dd
将其输出打印到(其)stderr,这是sh -c ...
的stderr,这是您的标准输出。
如果你跑:
time 2>file dd if=/dev/zero of=ddfile bs=512 count=125
您将在stderr(例如,屏幕)上获得time
的stderr输出,并在文件dd
上获得file
的stderr。 (无论你在2>file
部分滑动多远,只要它仍然是简单命令的一部分,就会发生这种情况。)
如果您尝试:
2>file time ...
你会发现time
的输出重定向,但这会完全击败内置的time
,而是运行/usr/bin/time
。为了让bash的内置功能成为可能,time
必须在前面。你可以创建一个子shell:
(time ...) 2>file
或子块pje illustrated:
{ time ...; } 2>file
(语法是笨拙的,子块作为空格和/或分号是必需的,但它避免了fork
系统调用。)