1

我有这个:

$ time 2>&1 sh 2>&1 -c "dd if=/dev/zero of=ddfile bs=512 count=125 && sync" > file

125+0 条记录

125+0 条记录

复制了 64000 字节 (64 kB),0.000617678 秒,104 MB/秒

实际0m0.133s

用户 0m0.000s

系统 0m0.020s

$ cat file

文件为空。

问题:我都了解dd并且time正在将他们的 o/p 发送到 stderr。但是由于我将 stderr 重定向到 stdout for timeand sh(这是 的父进程dd)并且还将 stdout 发送到文件,所以我希望将内容写入文件。为什么那没有发生?

4

2 回答 2

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
于 2013-09-12T01:02:57.747 回答
3

首先,除了一些例外,重定向通常发生在它们被写入的地方。它们从命令和参数序列中删除;只有剩余的、非重定向的单词参与。因此:

3>&1 foo 1>&2 arg1 2>&3 arg2 3>&- arg3

交换 stdout 和 stderr运行foo arg1 arg2 arg3,因为:

  1. 3>&1dup2在 fd 3 上制作 fd 1 (stdout)的副本(更准确地说是 a )
  2. 1>&2在 fd 1 上复制 fd 2 (stderr) (所以现在 stdout 和 stderr 都去他们要去的任何地方)
  3. 2>&3在 fd 2 (stderr) 上复制 fd 3 (保存的原始标准输出)
  4. 3>&-关闭 fd 3。

(值得注意的例外是管道输出“首先发生”,即使管道符号位于简单命令部分的末尾。)

其次,正如 pje 所指出的,time它是内置的 bash。 time foo运行命令,然后将时间摘要打印到 bash 的标准错误。首先time有效地删除关键字,然后照常处理剩余的命令序列。(即使命令是管道,这也适用:time乘以整个管道。)

在这种情况下,命令序列是一个简单的命令,带有重定向:

2>&1 sh 2>&1 -c ... > file

每个重定向都发生在它被写入的地方,剩下的顺序是:

sh -c ...

重定向是:

  1. 将 stderr 发送到 stdout 当前所在的任何位置
  2. 再次将标准错误发送到标准输出(这没有新效果)
  3. 将标准输出发送到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系统调用)。

于 2013-09-12T04:12:10.463 回答