PowerShell stderr重定向到文件插入换行符
编辑:我为这种行为创建了一个PowerShell UserVoice(反对?);请随意投票 当我重定向到文件时,PowerShell(5.1.16299.98,Windows 10 Pro 10.0.16299)正在向我的stderr中插入换行符,就像为控制台格式化一样。让我们生成任意长度的错误消息:PowerShell stderr重定向到文件插入换行符,powershell,stderr,io-redirection,Powershell,Stderr,Io Redirection,编辑:我为这种行为创建了一个PowerShell UserVoice(反对?);请随意投票 当我重定向到文件时,PowerShell(5.1.16299.98,Windows 10 Pro 10.0.16299)正在向我的stderr中插入换行符,就像为控制台格式化一样。让我们生成任意长度的错误消息: 类程序 { 静态void Main(字符串[]参数) { System.Console.Error.WriteLine(新字符串('x',int.Parse(args[0])); } } 我把上
类程序
{
静态void Main(字符串[]参数)
{
System.Console.Error.WriteLine(新字符串('x',int.Parse(args[0]));
}
}
我把上面的代码编译成了longerr.exe
。然后我这样称呼它:
$ .\longerr.exe 60 2>error.txt
.\longerr.exe $_ 2>&1 |
% {
if ($_ -is [System.Management.Automation.ErrorRecord]) {
$_.Exception.Message | Out-File -FilePath $f -Append
}
}
我在窗口宽度为60的PowerShell控制台中运行了以下脚本:
$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 60 2>error.txt
.\longerr.exe $_ 2>&1 |
% {
if ($_ -is [System.Management.Automation.ErrorRecord]) {
$_.Exception.Message | Out-File -FilePath $f -Append
}
}
首先,该文件的所有打开和关闭都可能很慢(我知道我可以添加更多代码并使用StreamWriter
),其次,该方法仍然存在一个问题(bug?),在本问题中我将不进行讨论
为了进行合理性检查,我在cmd.exe
中运行了longerr.exe 10002>test.txt
;它没有插入虚假的换行符。多亏我指出了这个问题,我已经解决了我问题中的两个问题——主要问题和我在最后提到的问题。关键在于:
$ Get-Content $f | Select-String '^(?![+\t]|At line| )'
可执行文件的stderr
上的完整输出只需在System.Management.Automation.ErrorRecord
类型的多个对象之间分割即可。实际拆分似乎是不确定的(*)。此外,部分字符串存储在属性Exception
中,而不是TargetObject
中。只有第一个ErrorRecord
具有非空的TargetObject
⋮
(*)它取决于与Powershell的读取调用相关的程序的写入/刷新调用顺序。如果在下面的测试程序中,在每个fprintf()之后添加一个fflush(stderr),将会有更多的ErrorRecord对象。除了第一条似乎是确定的,其中一些包含2条输出线,另一些包含3条输出线
有了这个,我可以修改longerr.exe
,也可以重现我最后提到的bug:
类程序
{
静态void Main(字符串[]参数)
{
如果(args.Length==1)
{
System.Console.Error.WriteLine(新字符串('x',int.Parse(args[0]));
}
其他的
{
for(int i=0;i
下面是PowerShell脚本,它可以(高效地)工作:
注:
TargetObject
的测试,我将消除我在问题中所关注的主要问题,但我仍然会得到我在最后提到的“bug”,这是链接的SO问题所解决的Out File
(使用-NoNewline
)而不是StreamWriter
,但这有两个问题:
error.txt
和success.txt
的目录)时慢了一个数量级StreamWriter
的性能也比out File
高出一个数量级。作为参考,我使用了一个存储
和>
。PowerShell 6.0默认值仅供参考cmd.exe
的以下功能,这绝对是一个荒谬的工作量:
$ .\longerr.exe 2000 4 2>error.txt
可能相关:@tessellingheckler:谢谢!这解决了我在问题末尾提到的问题,并且需要切换到一种编程模式,以避免我问题的主要问题。我贴了一个详细的答案。如果你想避免使用
cmd.exe
,这是一个非常丑陋的解决方案,但至少这是一个解释。