Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change 'standard error' to 'standard output'

I have a PowerShell script that writes to the error output. The script can be as simple as the following:

Write-Error 'foo'
Start-Sleep -s 5
Write-Error 'bar'

The script I actually call spawns an external process that takes a while to process and writes to standard error.

Now when I call the script like this:

. myScript.ps1

I get the error message with PowerShell's usual behaviour (i.e. red text and lots of debugging information). As that text has no relation to PowerShell in my actual application, I don't need those debugging information and it only makes the result less readable (and impossible to process).

Is there a way to redirect that output directly into standard output, so that I just get the text?

I tried something like this:

Write-Host ( . myScript.ps1 2>&1 )

But that delays the output until everything is completed.

About the “debugging information”, when I run the script right now, the output looks like this (in red):

C:\path\to\myScript.ps1 : foo
Bei Zeile:1 Zeichen:2
+ . <<<<  'C:\path\to\myScript.ps1'
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,myScript.ps1

C:\path\to\myScript.ps1 : bar
Bei Zeile:1 Zeichen:2
+ . <<<<  'C:\path\to\myScript.ps1'
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,myScript.ps1

When I run the script with Write-Host ( . myScript.ps1 2>&1 ), where the error output is written to the standard output, I get a result like this:

foo bar

That is exactly what I would like the output to be, except that the Write-Host (..) makes the output only appear after the script has terminated, so I cannot receive any information on the progress of said script.

To come actually closer to my actual problem (because it’s hard to explain that with pure PowerShell); I’ve got the following Python script that resembles approximately what the command line program I use does, i.e. it does some processing and prints out the progress to the standard error:

#!/usr/bin/python
import sys, time
sys.stderr.write( 'Progressing... ' )
sys.stderr.flush()
time.sleep( 5 )
sys.stderr.write( 'done.\n' )
sys.stderr.flush()

Now, when I call it with python script.py, it works correctly and prints out the “progressing” line, waits 5 seconds and then prints the “done” to PowerShell (as normal text). The problem is now that I want to run this in a job, like this: Start-Job { python script.py }.

The job gets started correctly, and also works fine in the background, but when I want to check its progress via Receive-Job <id>, I get no output at all at first, and after the script/program finished (i.e. after the 5 seconds), I get the following output (in red again):

Progressing... done.
    + CategoryInfo          : NotSpecified: (Progressing... done.:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

Obviously that is not what I am trying to get. Instead I want to get the actual output that was printed to the standard error, both live (i.e. when it happens in the script) and without that PowerShell related debugging text.

like image 852
poke Avatar asked May 28 '11 18:05

poke


People also ask

How do you redirect standard error to standard output?

Understanding the concept of redirections and file descriptors is very important when working on the command line. To redirect stderr and stdout , use the 2>&1 or &> constructs.

Which symbol should I use to redirect the error output to the standard output?

The regular output is sent to Standard Out (STDOUT) and the error messages are sent to Standard Error (STDERR). When you redirect console output using the > symbol, you are only redirecting STDOUT. In order to redirect STDERR, you have to specify 2> for the redirection symbol.


1 Answers

According to the edit section of the question, this should be suitable:

. MyScript.ps1 2>&1 | %{ Write-Host $_ }

It writes just "foo" and "bar" and they appear as soon as they happen.

EDIT

Actually this is even simpler and works fine, too:

. MyScript.ps1 2>&1 | Write-Host

But I keep the original answer. That code allows to process the output ($_) dynamically and do something else (i.e. not just write it to the host).

EDIT 2

External program that writes to STDERR:

using System;
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            for (int i = 0; i < 100; ++i)
            {
                Console.Error.WriteLine("Step " + i);
                System.Threading.Thread.Sleep(2000);
            }
        }
    }
}

The script that starts this application as a job and receives its output periodically.

$ErrorActionPreference = 'continue'

$job = Start-Job { C:\TEMP\Test\ConsoleApplication1.exe 2>&1 }
for(;;) {
    Receive-Job $job | Write-Host
    Start-Sleep 2
}

The script does exactly what you need (for your edit 2 section): it shows the output as soon as it is available and it does not show unwanted extra error information.

P.S. This version works, too:

$job = Start-Job { C:\TEMP\Test\ConsoleApplication1.exe }
for(;;) {
    Receive-Job $job 2>&1 | Write-Host
    Start-Sleep 2
}
like image 108
Roman Kuzmin Avatar answered Sep 18 '22 20:09

Roman Kuzmin