开发者

Change 'standard error' to 'standard output'

开发者 https://www.devze.com 2023-03-09 12:51 出处:网络
I have a PowerShell script that writes to the error output. The script can be as simple as the following:

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... d开发者_C百科one.: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.


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
}


Try:

$erroractionpreference = "silentlycontinue"
.\myscript.ps1
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号