powershell stderr重定向以插入新线



编辑:我为(反对?(创建了一个powershell uservoice"建议";随意投票。

powershell(5.1.16299.98,Windows 10 Pro 10.0.16299(正在将新线插入我的stderr时,当我重定向到文件时,就像为控制台格式化一样。让我们生成任意长度的错误消息:

class Program
{
    static void Main(string[] args)
    {
        System.Console.Error.WriteLine(new string('x', int.Parse(args[0])));
    }
}

我将上述内容编译到longerr.exe。然后我这样称呼:

$ .longerr.exe 60 2>error.txt

我在带有窗口宽度的PowerShell控制台中运行以下脚本60:

$h = '.longerr.exe : '.Length
$w = 60 - 1
$f = 'error.txt'
Remove-Item $f -ea Ignore
(($w-$h), ($w-$h+1), ($w), ($w+1), ($w*2-$h), ($w*2-$h+1)) |
    % { 
        $_ >> $f
        .longerr.exe $_ 2>>$f
    }

现在在更宽的控制台中,我运行以下内容:

$ Get-Content $f | Select-String '^(?![+t]|At line|  )'

(我本来可以在文本编辑器和修剪线中打开文件。(这是输出:

43
.longerr.exe : xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
44
.longerr.exe : 
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
59
.longerr.exe : 
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
60
.longerr.exe : xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxx
102
.longerr.exe : xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
103
.longerr.exe : xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
x

为什么Powershell这样做?我可以停止吗?我宁愿不必做这样的事情:

        .longerr.exe $_ 2>&1 |
            % {
                if ($_ -is [System.Management.Automation.ErrorRecord]) {
                    $_.Exception.Message | Out-File -FilePath $f -Append
                }
            }

首先,该文件的所有打开和关闭都可以很慢(我知道我可以添加更多代码并使用 StreamWriter(,其次,仍然存在问题(bug?(这种方法,我不会在这个问题中提出。

为了进行理智检查,我在 cmd.exe中运行了 longerr.exe 1000 2>test.txt;它没有插入虚假的线路。

感谢TessellingHeckler的评论,指出了我的问题,为什么PowerShell将powershell chops在stderr上发给我?在最后。关键是以下内容:

可执行文件的stderr上的完整输出仅在类型System.Management.Automation.ErrorRecord的几个对象上拆分。实际分裂似乎是非确定性(*(。此外,部分字符串存储在属性Exception中而不是TargetObject中。只有第一个ErrorRecord具有非零TargetObject

(*(这取决于程序与PowerShell的读取有关的程序的写入/冲洗调用的顺序。如果在下面的测试程序中每个fprintf((之后添加了一个fflush(stderr(,则会有更多的errorrecord对象。除了似乎是确定性的第一个,其中一些包括2条输出线,其中一些线3。

这样,我能够修改longerr.exe,也可以重现我在最后提到的错误:

class Program
{
    static void Main(string[] args)
    {
        if (args.Length == 1)
        {
            System.Console.Error.WriteLine(new string('x', int.Parse(args[0])));
        }
        else
        {
            for (int i = 0; i < int.Parse(args[1]); i++)
            {
                System.Console.Error.WriteLine("n");
                System.Console.Error.WriteLine(new string('x', int.Parse(args[0])));
            }
        }
    }
}

这是有效(有效(的PowerShell脚本:

$p_out = 'success.txt'
$p_err = 'error.txt'
try
{
    [Environment]::CurrentDirectory = $PWD
    $append = $false
    $out = [System.IO.StreamWriter]::new($p_out, $append)
    $err = [System.IO.StreamWriter]::new($p_err, $append)
    .longerr.exe 2000 4 2>&1 |
        % {
            if ($_ -is [System.Management.Automation.ErrorRecord]) {
                # https://stackoverflow.com/a/33858097/2328341
                if ($_.TargetObject -ne $null) {
                    $err.WriteLine(); 
                }
                $err.Write($_.Exception.Message)
            } else {
                $out.WriteLine($_)
            }
        }
}
finally
{
    $out.Close()
    $err.Close()
}

注意:

  1. 如果没有TargetObject的测试,我将消除我在问题中关注的主要问题,但是我仍然会在最后提到的"错误",链接的问题地址。
  2. 我可以使用Out-File(带有-NoNewline(而不是StreamWriter,但是有两个问题:
    1. Windows Defender正在使所有文件打开并关闭的数量级要比我关闭"实时保护"(全球或包含error.txtsuccess.txt的目录(时。
    2. 即使没有防守者减慢事情的速度,StreamWriter也会超过Out-File。供参考,我正在使用三星960 EVO进行存储。
  3. StreamWriter(string, bool)构造函数将UTF-8写入没有字节订单标记(BOM(,而PowerShell 5.1的重定向操作员>>>将UTF-16 LE与BOM一起使用。作为参考,PowerShell 6.0默认为UTF-8,没有BOM。

(在现实世界中,我包括了完整性的Stdout。(现在,这是一个绝对可笑的工作以获取cmd.exe的以下功能:

$ .longerr.exe 2000 4 2>error.txt

相关内容

  • 没有找到相关文章

最新更新