Search code examples
linuxshellstdoutpipeline

How do I pass output of (both) piped instructions to file?


I have two commands say cmd1 and cmd2, wherein i perform

time cmd1 | cmd2

I want to get something like

cmd1 >> file.out and {time cmd1 >> file.out} | cmd2 >> file.out

so can someone suggest how it is actually done? edit: as Anthony's answer below suggests, tee works here but if i write

time cmd1 |tee -a file.out | cmd2 >> file.out

then it only writes the output of cmd1 to file.out and cmd2 to file.out, whereas i also want the output of {time cmd1} to that file.

I am using bash shell on Ubuntu Mate. If the time keyword complicates it, please suggest some method to time the execution and do the exact operation.


Solution

  • If I understand your question correctly, you want the output of cmd to be written to file.out and also used as the input to cmd2. For this case, you could try inserting the tee command (with the -a option to append) into your command pipeline:

    cmd1 | tee -a file.out | cmd2 >> file.out
    

    Example

    $ printf "one\ntwo\nthree\n" | tee -a file.out | sed 's/.*/\U&/' >> file.out
    
    $ cat file.out
    one
    two
    three
    ONE
    TWO
    THREE
    

    Answer to edited version of the question

    The following construct should do what you want:

    { time cmd1; }  2>> file.out | tee -a file.out | cmd2 >> file.out
    

    Since the time utility provided by Bash operates on the complete pipeline, curly braces are used to group these commands so that they can be considered as a whole. Note: the terminating semi-colon (;) is required before the closing brace.

    The standard out stream of cmd1 is piped through to the tee command but since Bash’s time utility prints its timing statistics to standard error, the file descriptor 2 is redirected so that the timing statistics are appended to file.out.

    Modified version of previous example

    { time printf "one\ntwo\nthree\n"; }  2>> file.out | tee -a file.out | sed 's/.*/\U&/' >> file.out