Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

time writes to stderr, so one would assume that adding 2>&1 to the command line should route its output to stdout. But this does not work:

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

Only with parentheses it works:

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

Why are parentheses needed in this case? Why isn't time wc interpreted as one single command?

share|improve this question
3  
Note that the results will differ depending on whether time is the shell keyword, or /usr/bin/time. There might be several sets of descriptors involved here (the shell's, and those attached to a time process). And let's not forget about those implied by the () subshell. (waiting for a bash specialist :p) – John WH Smith Jan 19 at 13:29
up vote 22 down vote accepted

In ksh, bash and zsh, time is not a command (builtin or not), it's a reserved word in the language like for or while.

It's used to time a pipeline1.

In:

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

You have special syntax that tells the shell to run that pipe line:

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

And report timing statistics for it.

In:

time cmd > output 2> error

It's the same, you're timing the cmd > output 2> error command, and the timing statistics still go on the shell's stderr.

You need:

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

Or:

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

For the shell's stderr to be redirected to timing-output before the time construct (again, not command) is used (here to time cmd > output 2> error 3>&-).

You can also run that time construct in a subshell that has its stderr redirected:

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

But that subshell is not necessary here, you only need stderr to be redirected at the time that time construct is invoked.

Most systems also have a time command. You can invoke that one by disabling the time keyword. All you need to do is quote that keyword somehow as keywords are only recognised as such when literal.

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

But beware the format may be different and the stderr of both time and cmd will be merged into error-and-timing-output.

Also, the time command, as opposed to the time construct cannot time pipelines or compound commands or functions or shell builtins...

If it were a builtin command, it might be able to time function invocations or builtins, but it could not time redirections or pipelines or compound commands.


1 Note that bash has (what can be considered as) a bug whereby time (cmd) 2> file (but not time cmd | (cmd2) 2> file for instance) redirects the timing output to file

share|improve this answer
    
Well, I often stress my head to remember that time is a keyword, not a shell builtin. – cuonglm Jan 19 at 14:41
    
Thanks for the tip about using 'time' to get the executable-- handier than writing /usr/bin/time (or even command time :-)). – alexis Jan 29 at 9:34

There's no command named time wc, time and wc are separated word in shell.

Now, there're often two separate program named time, the one is shell keyword, another one is external command. In shells which time is a shell keyword, when you type time wc ..., the shell used its keyword time instead of the external time utility.

When the shell uses time keyword, it does not need to fork() new process, the current time standard in and standard error are not changed. The redirection part in:

time wc file > wc.out 2>&1

affects wc only.

When you use compound command (list):

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

the shell ran time wc file inside a subshell, (time wc file) was considered a single command, and the redirection part affects its standard output and standard error, which now include both time and wc.


You can make the same effect, without the cost of forking new process by using another form of grouping command {list;}:

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

If you use external time, then you don't face this problem, because it was run in new process:

/usr/bin/time wc file > wc.out 2>&1
share|improve this answer
    
+1 nice explanations – Joe Jan 23 at 8:14

Because time you're executing is bash builtin. Bash processes it in such special way.

If you will use real time binary, it will act exactly in the way you expect it:

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

Though the output of this time is a bit different:

 $ /usr/bin/time wc file > wc.out 
0.00user 0.00system 0:00.00elapsed ?%CPU (0avgtext+0avgdata1900maxresident)k
0inputs+8outputs (0major+82minor)pagefaults 0swaps
share|improve this answer
8  
If it was a builtin, it wouldn't be a problem. The problem is that it's a keyword in the language. time cmd > output times the cmd > output command, and time foo | bar times foo | bar. – Stéphane Chazelas Jan 19 at 14:24

It is not time that writes the time information. The builtin time makes the shell write this after the command has completed. But redirection affects only the command.

In the (time ...) case the redirection is applied to the whole subshell.

share|improve this answer

Because time is a shell builtin, it writes to the shell's stderr, rather than the command's stderr.

Using parentheses forces the whole command into a child shell whose stderr can be redirected.

using curly brackets produces a similar result without actually starting a subshell

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

(yes, you need the semicolon)

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.