2>NUL in PowerShell

We can have PowerShell eat an .exe’s STDOUT very easily:

xcopy file.txt target.txt | Out-Null;

We can have it eat both STDOUT and STDERR by redirecting STDERR into STDOUT

xcopy file.txt target.txt 2>&1 | Out-Null;
xcopy “ThisFileDoesn’tExist.ps1” target.txt 2>&1 | Out-Null;

Unix’s filehandles are somewhat clever.  You can redirect STDOUT to a file, then redirect STDERR into STDOUT, and eat STDOUT.  This nukes STDERR.  I’ll leave the advisablity of this to the user.

cp Schroedinger.txt target.txt> found.txt 2>&1 > dev/null

However, this doesn’t work in PowerShell:

xcopy Schroedinger.txt target.txt | Set-Content found.txt 2>&1 | Out-Null

If worst comes to worst, we can use cmd.exe to do this.

cmd /c xcopy Schroedinger.txt target.txt “2>NUL”

Ugh.  Anyone have any better ideas?



Comments (2)

  1. CodeMaster Bob says:

    Slight errors with the Unix redirection. (The following syntax analysis is based on Bourne Shell.)

    Firstly, the default I/O handles (file descriptors in Unish) belong to the process not the system. STDOUT is the default output handle (1) of the process, not the name of the system console. When the output is redirected to a file, its connection to the console (or to whatever it used to be connected) is replaced with a different connection but it is still STDOUT. Thus the implication that 2>&1 redirects to the now unused STDOUT is incorrect.

    Secondly, redirections are done in the order listed and do not delete handles (but can close them, vis. X>&-). The above command:

    cp Schroedinger.txt target.txt> found.txt 2>&1 > dev/null

    1-Connects STDOUT (handle 1) to found.txt

    2-DUPLICATES handle 1 as handle 2 (STDERR) so both are now connected to found.txt

    3-Connects STDOUT to /dev/null.

    Assuming that the repeated attempt to redirect stdout is permitted, the final result is:

    STDOUT connected to /dev/null

    STDERR connected to found.txt

    Probably not what was intended. The correct command for what I think was intended would be:

    cp Schroedinger.txt target.txt >found.txt 2>/dev/null

    Exactly the same* as cmd.exe AND Powershell. BTW, it should be noted that cp (like most simple Unix commands) writes nothing to STDOUT. The only messages are error messages to STDERR. (Unlike DOS copy but exactly like DOS rename.) To know if the command succeeded (apart from the LACK of an error message) check if $? is 0. (Also the same in Powershell. Coincidence?) For cmd use %ERRORLEVEL%.

    (*Except that /dev/null is NUL: in cmd and $null in Powershell V2+ (V1?). Strictly speaking, the name of the null file in Powershell is an empty string  ("" or '', i.e. [string]$null))

    Further, for the Powershell example given above:

    xcopy Schroedinger.txt target.txt | Set-Content found.txt 2>&1 | Out-Null

    I believe the error here is that the redirection in Set-Content can only affect error objects being generated by Set-Content. There is no control over objects already in the error stream (from the xcopy). Again, the correct command is:

    xcopy Schroedinger.txt target.txt >found.txt 2>$null

    Another interesting fact. Errors from native commands (as text on STDERR) are converted to error objects encapsulating the text when attached to STDOUT. As in:

    xcopy non-existent1 non-existent2 2>&1 | Get-Member

    CAVEAT: I have no access to Powershell V1 so this analysis might be totally inapplicable for that case.

  2. timid says:

    Wow!  Thanks for the detailed corrections!