Search code examples
bashunixkshfile-descriptor

Unix Shell File Descriptors


I need to run a program called pg.sh. It report stdout to output log. How do I save stdout and both stderr and stdout into 2 separate log files?

I searched and got the below code

(pg.sh 2>&1 1>&3 ) 3>&1 1>&2 | tee output.log) > final.log 2>&1

I understand 1 and 2 are File Descriptors pointing to stdout and stderr. 3 is another File Descriptor pointing to stdout.

The above code works fine, But I do not understand how this is being achieved. Could some one help me with the code written?


Solution

  • starting from the outer redirection: ( .. ) 3>&1 1>&2 , the order is important:

    • fd 3 is open for write as duplicate of 1 (stdout: here it's the pipe input)
    • then fd 1 is crushed as duplicate of 2 (stderr) (or redirected to stderr)

    the | input is then the fd 3, whereas the stderr is not captured by tee,

    The nested redirection:

    • fd 2 is redirected to stdout (which was redirected to outer stderr)

    • fd 1 is redirected to fd 3 (which was redirected to outer stdout)

      as tee duplicates output logged, (the final redirection >final.log 2>&1, as the fd 2 is open after fd 1 they are both redirected to final.log) the file final.log will contain program stdout and stderr, but output.log only stdout.

    Maybe it could be written easier, using 3>&1 1>&2 2>&3 which reverses stdout and stderr.

    The following should do the same:

    ( pg.sh | tee output.log ) >final.log 2>&1
    

    The following writes program stdout to output.log stderr to error.log and both to final.log.

    ( ( pg.sh | tee output.log ) 3>&1 1>&2 2>&3 | tee error.log ) >final.log 2>&1