How do I write stderr to a file while using “tee” with a pipe?

前端 未结 10 943
独厮守ぢ
独厮守ぢ 2020-11-22 08:01

I know how to use tee to write the output (STDOUT) of aaa.sh to bbb.out, while still displaying it in the terminal:

相关标签:
10条回答
  • 2020-11-22 08:59

    I'm assuming you want to still see STDERR and STDOUT on the terminal. You could go for Josh Kelley's answer, but I find keeping a tail around in the background which outputs your log file very hackish and cludgy. Notice how you need to keep an exra FD and do cleanup afterward by killing it and technically should be doing that in a trap '...' EXIT.

    There is a better way to do this, and you've already discovered it: tee.

    Only, instead of just using it for your stdout, have a tee for stdout and one for stderr. How will you accomplish this? Process substitution and file redirection:

    command > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2)
    

    Let's split it up and explain:

    > >(..)
    

    >(...) (process substitution) creates a FIFO and lets tee listen on it. Then, it uses > (file redirection) to redirect the STDOUT of command to the FIFO that your first tee is listening on.

    Same thing for the second:

    2> >(tee -a stderr.log >&2)
    

    We use process substitution again to make a tee process that reads from STDIN and dumps it into stderr.log. tee outputs its input back on STDOUT, but since its input is our STDERR, we want to redirect tee's STDOUT to our STDERR again. Then we use file redirection to redirect command's STDERR to the FIFO's input (tee's STDIN).

    See http://mywiki.wooledge.org/BashGuide/InputAndOutput

    Process substitution is one of those really lovely things you get as a bonus of choosing bash as your shell as opposed to sh (POSIX or Bourne).


    In sh, you'd have to do things manually:

    out="${TMPDIR:-/tmp}/out.$$" err="${TMPDIR:-/tmp}/err.$$"
    mkfifo "$out" "$err"
    trap 'rm "$out" "$err"' EXIT
    tee -a stdout.log < "$out" &
    tee -a stderr.log < "$err" >&2 &
    command >"$out" 2>"$err"
    
    0 讨论(0)
  • 2020-11-22 08:59

    To redirect stderr to a file, display stdout to screen, and also save stdout to a file:

    ./aaa.sh 2>ccc.out | tee ./bbb.out

    EDIT: To display both stderr and stdout to screen and also save both to a file, you can use bash's I/O redirection:

    #!/bin/bash
    
    # Create a new file descriptor 4, pointed at the file
    # which will receive stderr.
    exec 4<>ccc.out
    
    # Also print the contents of this file to screen.
    tail -f ccc.out &
    
    # Run the command; tee stdout as normal, and send stderr
    # to our file descriptor 4.
    ./aaa.sh 2>&4 | tee bbb.out
    
    # Clean up: Close file descriptor 4 and kill tail -f.
    exec 4>&-
    kill %1
    
    0 讨论(0)
  • 2020-11-22 09:00

    In my case, a script was running command while redirecting both stdout and stderr to a file, something like:

    cmd > log 2>&1
    

    I needed to update it such that when there is a failure, take some actions based on the error messages. I could of course remove the dup 2>&1 and capture the stderr from the script, but then the error messages won't go into the log file for reference. While the accepted answer from @lhunath is supposed to do the same, it redirects stdout and stderr to different files, which is not what I want, but it helped me to come up with the exact solution that I need:

    (cmd 2> >(tee /dev/stderr)) > log
    

    With the above, log will have a copy of both stdout and stderr and I can capture stderr from my script without having to worry about stdout.

    0 讨论(0)
  • 2020-11-22 09:05

    If you're using zsh, you can use multiple redirections, so you don't even need tee:

    ./cmd 1>&1 2>&2 1>out_file 2>err_file
    

    Here you're simply redirecting each stream to itself and the target file.


    Full example

    % (echo "out"; echo "err">/dev/stderr) 1>&1 2>&2 1>/tmp/out_file 2>/tmp/err_file
    out
    err
    % cat /tmp/out_file
    out
    % cat /tmp/err_file
    err
    

    Note that this requires the MULTIOS option to be set (which is the default).

    MULTIOS

    Perform implicit tees or cats when multiple redirections are attempted (see Redirection).

    0 讨论(0)
提交回复
热议问题