Search code examples
windowsbatch-filecmdstdoutstderr

Windows Redirect STDERR and STDOUT to same program when piping


MSDN and this question give an example of redirecting Windows cmd stdout and stderr to a single file:

dir file.xxx 1> output.msg 2>&1

I'm looking to do the same when the STDERR and STDOUT are piped to another program. Here's the usage without the STDERR redirects:

net use Z: \\server\share  |  TimeStampPipe.exe >> logfile.txt 

I want the STDERR and STDOUT of "net use" to be piped into TimeStampPipe.exe. I don't care about STDERR from TimeStampPipe.exe. Where does the 2>&1 go to indicate that it applies to net use and not to TimeStampPipe.exe? I tried this

net use Z: \\server\share  1> 2>&1 TimeStampPipe.exe >> logfile.txt 

and got 2>&1 was unexpected at this time.

I tried this

net use Z: \\server\share  1| 2|&1 TimeStampPipe.exe >> logfile.txt 

and got & was unexpected at this time.

Is there a way to do this when piping? I could try something like:

net use Z: \\server\share  1> tempfile.txt 2>&1
type tempfile.txt | TimeStampPipe.exe >> logfile.txt 
del tempfile.txt

Is there a more concise approach?

Edit: I tried the suggestion of @compo to use 2>&1 alone. I tried these three forms:

net use Z: \\server\share  | 2>&1 TimeStampPipe.exe >> logfile.txt 
net use Z: \\server\share  |  TimeStampPipe.exe 2>&1 >> logfile.txt 
net use Z: \\server\share  | TimeStampPipe.exe >> logfile.txt 2>&1

In each case, the stdout is correctly piped, but any stderr output from net use goes to the screen, not through the pipe.


Solution

  • As others already pointed out in comments you have to do this:

    net use Z: \\server\share 2>&1 | TimeStampPipe.exe >> logfile.txt
    

    You already have got the right code to redirect both STDOUT and STDERR to a file:

    dir file.xxx 1> output.msg 2>&1
    

    which is the same as:

    dir file.xxx > output.msg 2>&1
    

    because output redirection (>) reads from STDOUT (handle 1) by default.

    The expression 2>&1 defines that handle 2 (STDERR) is to be redirected to the destination that handle 1 (STDOUT) is currently (re-)directed to. The position of that expression is crucial.


    For a pipe (|) you have to apply the same technique. Remember that a pipe redirects the output (at STDOUT, handle 1) of the left-side command into the input (at STDIN, handle 0) of the right-side command.

    Now we want to redirect both STDOUT and STDERR of the left side into STDIN of the right side. Since nothing changes for the right side we keep it untouched. The left side however needs to be modified; STDOUT already goes where we want to, but STDERR does not yet, so we have to redirect it to the target of STDOUT, by using the same expression as for output redirection (>):

    net use Z: \\server\share 2>&1 | TimeStampPipe.exe >> logfile.txt