在文件中写入“时间”的输出,为什么需要括号?


18

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解释为一个命令?


3
请注意,结果取决于timeshell关键字还是/usr/bin/time。这里可能涉及几组描述符(shell的描述符,以及那些附加到time进程的描述符)。而且,我们不要忘记()subshel​​l 所隐含的内容。(正在等待bash专家:p)
约翰·W·史密斯

Answers:


24

kshbash而且zshtime不是一个命令(内建或没有),它在像语言的保留字forwhile

它用于给管道计时1

在:

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

您具有告诉外壳程序运行该管道的特殊语法:

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

并为其报告时序统计信息。

在:

time cmd > output 2> error

这是相同的,你定时cmd > output 2> error命令,计时统计仍然走在外壳的标准错误。

你需要:

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

要么:

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

为了timing-output在使用时间构造(再次不是command)(此处为time cmd > output 2> error 3>&-)之前将外壳的stderr重定向到。

您还可以time在重定向了stderr 的子shell中运行该构造:

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

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

大多数系统还具有time命令。您可以通过禁用time关键字来调用该代码。您需要做的就是以某种方式引用该关键字,因为只有在字面意义上才识别出关键字。

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

但要注意的格式可能不同,两者的标准错误timecmd将合并到error-and-timing-output

而且,与构造time相反,该命令time无法对管道,复合命令或函数或Shell内置命令进行计时...

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


1请注意,它bash具有(可以被视为)一个错误,通过该错误time (cmd) 2> filetime cmd | (cmd2) 2> file例如,并非如此)将计时输出重定向到file


好吧,我经常强调我要记住,这time是一个关键字,而不是内置的shell。
cuonglm '16

感谢您提供有关'time'获取可执行文件的技巧- 比编写/usr/bin/time(或什至是command time:-)更方便。
亚历克西斯

@alexis也\time
ctrl-alt-delor

7

没有名为的命令time wctime并且在shell中wc是分隔的单词

现在,通常有两个名为的单独程序time,一个是shell关键字,另一个是external命令。在time作为shell关键字的shell中,键入时time wc ...,shell使用其关键字time而不是外部时间实用程序

当shell使用time关键字时,它不需要fork()新进程,当前的time标准输入和标准错误都不会改变。重定向部分包括:

time wc file > wc.out 2>&1

wc仅影响。

使用复合命令时(list)

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

外壳程序运行time wc file在子外壳程序中,(time wc file)被视为单个命令,重定向部分会影响其标准输出和标准错误,现在包括timewc


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

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

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

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

是否有使用之间的任何实际差别time/usr/bin/time?可执行文件在功能上是否相同?
Hashim

2

因为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

9
如果它是内置的,那不是问题。问题在于它是语言中的关键字time cmd > outputcmd > output命令,和time foo | barfoo | bar
斯特凡Chazelas

1

不是time写时间信息。内置time命令使外壳程序在命令完成后将其写入。但是重定向仅影响命令。

在这种(time ...)情况下,重定向将应用于整个子外壳。


0

因为时间是内置的shell,所以它写入shell的stderr,而不是命令的stderr。

使用括号会强制整个命令进入子外壳,其stderr可以重定向。

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

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

(是的,您需要分号)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.