将“time”的输出写入文件中,为什么需要括号?

将“time”的输出写入文件中,为什么需要括号?

time写入stderr,因此有人认为添加2>&1到命令行应该将其输出路由到stdout。但这并不奏效:

test@debian:~$ cat file 
one two three four
test@debian:~$ time wc file > wc.out 2>&1

real    0m0.022s
user    0m0.000s
sys     0m0.000s
test@debian:~$ cat wc.out 
 1  4 19 file

只有使用括号才有效:

test@debian:~$ (time wc file) > wc.out 2>&1
test@debian:~$ cat wc.out 
 1  4 19 file

real    0m0.005s
user    0m0.000s
sys     0m0.000s

在这种情况下为什么需要括号?为什么不被time wc解释为一张单曲命令?

答案1

ksh, bashand中zshtime不是命令(是否内置),它是语言中的保留字,如foror while

它用于对管道1进行计时。

在:

time for i in 1 2; do cmd1 "$i"; done | cmd2 > redir

您有特殊的语法告诉 shell 运行该管道:

for i in 1 2; do cmd1 "$i"; done | cmd2 > redir

并报告其时间统计数据。

在:

time cmd > output 2> error

是一样的,你也是定时cmd > output 2> error命令和计时统计信息仍然显示在 shell 的 stderr 上。

你需要:

{ time cmd > output 2> error; } 2> timing-output

或者:

exec 3>&2 2> timing-output
time cmd > output 2> error 3>&-
exec 2>&3 3>&-

为了将 shell 的 stderr 重定向到timing-outputtime 构造之前(同样,不是命令)被使用(此处为时间cmd > output 2> error 3>&-)。

您还可以time子外壳其 stderr 已重定向:

(time cmd > output 2> error) 2> timing-output

time但是这个子 shell 在这里不是必需的,您只需要在调用该构造时重定向 stderr 即可。

大多数系统也有一个time命令。您可以通过禁用该关键字来调用该time关键字。您需要做的就是以某种方式引用该关键字,因为关键字只有在字面量时才会被识别。

'time' cmd > output 2> error-and-timing-output

但要注意格式可能不同,并且两者的 stderrtime都会cmd合并到error-and-timing-output.

此外,time与构造相反,命令time不能对管道或复合命令或函数或 shell 内置函数进行计时...

如果它是内置命令,它可能能够对函数调用或内置命令进行计时,但无法对重定向、管道或复合命令进行计时。


1请注意bash有(可以被视为)一个错误由此time (cmd) 2> file(但不是time cmd | (cmd2) 2> file例如)将计时输出重定向到file

答案2

没有名为 的命令time wctime并且wc是分开的单词在外壳中。

现在,经常有两个分开的程序name time,一个是 shell 关键字,另一个是外部命令。在 shell 中,它time是 shell 关键字,当您键入 时time wc ...,shell 使用其关键字time而不是外部时间效用

当shell使用time关键字时,不需要叉()新工艺中,现行time标准和标准差没有变化。重定向部分位于:

time wc file > wc.out 2>&1

仅影响wc

当你使用复合命令(list):

(time wc file) > wc.out 2>&1

shelltime wc file在子 shell 内运行,(time wc file)被认为是单身的命令,重定向部分影响其标准输出和标准错误,现在包括timewc


您可以通过使用另一种形式的分组命令来实现相同的效果,而无需创建新进程的成本{list;}

{time wc file;} > wc.out 2>&1

如果您使用 external time,那么您不会遇到这个问题,因为它是在新进程中运行的:

/usr/bin/time wc file > wc.out 2>&1

答案3

因为time你正在执行的是 bash 内置的。 Bash 以这种特殊的方式处理它。

如果您将使用真正的time二进制文件,它将完全按照您期望的方式运行:

/usr/bin/time wc file > wc.out 2>&1

虽然这次的输出有点不同:

 $ /usr/bin/time wc file > wc.out 
0.00user 0.00system 0:00.00elapsed ?%CPU (0avgtext+0avgdata1900maxresident)k
0inputs+8outputs (0major+82minor)pagefaults 0swaps

答案4

因为 time 是 shell 内置函数,所以它会写入的 stderr,而不是命令的 stderr。

使用括号强制将整个命令放入一个可以重定向 stderr 的子 shell 中。

使用大括号会产生类似的结果,而无需实际启动子 shell

  { time who ; } > /tmp/timwho >& /tmp/xx 

(是的,你需要分号)

相关内容