30

Suppose I have a binary called foo.

If I want to redirect the output of foo to some other process bar, I could write ./foo | bar.

On the other hand, if I wanted to time foo, and redirect the output of time I could write, time (./foo) | bar.

My question is, how can I stick the output of time to the end of the output of foo and pipe it through the same pipe?

The following solution is not what I am looking for, because it starts two separate instances of the process bar, while I want a single shared pipe, to a single instance of bar.

time (./foo | bar)  | bar

For anyone who is curious, the reason for not wanting to start two instances of bar is because bar can be a network client and I want the timing information to be sent to the server as part of the same http POST message as the process output.

merlin2011
  • 3,925
  • answered here, somewhat better answer: https://stackoverflow.com/questions/13356628/how-to-redirect-the-output-of-the-time-command-to-a-file-in-linux – JDS Jul 20 '18 at 14:45

3 Answers3

39

If I understand what you're asking for I this will do. I'm using the commands ls ~ and tee as stand-ins for ./foo and bar, but the general form of what you want is this:

$ ( time ./foo ) |& bar

NOTE: The output of time is already being attached at the end of any output from ./foo, it's just being done so on STDERR. To redirect it through the pipe you need to combine STDERR with STDOUT. You can use either |& or 2>&1 to do so.

$ ( time ./foo ) |& bar

-or-

$ ( time ./foo ) 2>&1 | bar

Example

$ ( time ls . ) |&  tee cmd.log
cmd.log
file1
file2
file3
file4
file5

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

And here's the contents of the file cmd.log produced by tee.

$ more cmd.log 
cmd.log
file1
file2
file3
file4
file5

real    0m0.005s
user    0m0.000s
sys     0m0.001s
slm
  • 369,824
  • Note that this syntax doesn't work for BASH. – jvriesem May 30 '18 at 18:50
  • 1
    @jvriesem all the examples are from bash – slm May 30 '18 at 22:55
  • The |& operator is not recognized at least as of v3.2.57. The knowledge I gained from this is the parentheses were necessary and create a subshell. – Govind Rai Feb 14 '20 at 18:21
  • |& shows up in Bash 4. Control operators is covered here BTW - https://unix.stackexchange.com/questions/159513/what-are-the-shells-control-and-redirection-operators. – slm Feb 14 '20 at 22:44
12

time sends its output to stderr instead of stdout by default. You just need to redirect that where you want it.

You say "On the other hand, if I wanted to time foo, and redirect the output of time I could write, time (./foo) | bar." but this is actually incorrect. In this case, the output of time would still be displayed on your console, only stdout would be redirected.

You can redirect stderr specifically with:

(time foo) 2>&1 | bar

or all pipes with:

(time foo) |& bar

The brackets are needed for this to work correctly.

7ochem
  • 141
Riot
  • 231
  • Thanks! Your answer helped me figure it out. The accepted answer mentions dollar sign in the beginning, I thought that's supposed to be part of the command and was confused why it wasn't working. – Abhijeet Singh Apr 27 '23 at 07:37
0

I found that this works on Solaris. (time ls) &> file