
[英]How can I do an unbuffered / live replacement in Powershells's output?
[英]Can I tee unbuffered program output in Powershell?
我正在尝试将 Putty 的 plink.exe 用作 Powershell 脚本的一部分,并且在打开 output 时遇到了麻烦。
一些命令调用交互式响应(例如:输入密码)。 具体来说,我正在针对 Isilon 进行测试。
示例代码:
$command = '&"C:\Program Files\Putty\plink.exe" root@10.0.0.141 -pw "password" -t -batch "isi auth users create testuser --set-password"'
iex $command
预期结果:
password:
confirm:
如果我尝试使用iex $command | tee-object -variable result
iex $command | tee-object -variable result
或什至只是使用iex $command *>test.log
重定向,提示文本直到我回复后才会显示。 虽然在技术上仍然可以正常工作,但如果您不确切知道会出现什么提示,那么它是无用的。
我试过使用 Start-Transcript,但这根本没有捕获 output。 我也尝试过使用 plink 的 -sshlog 参数,但是记录太多了,格式不可读。
有没有办法让标准输出在控制台中不受缓冲,并将其存储在变量中?
要回答一些潜在的问题:
-这是在不允许模块的环境中运行的,因此不能使用 Posh-SSH。
- 可用的 Powershell 版本不够新,无法使用内置的 openssh 功能。
这都是关于重定向流的。
当您使用重定向时,所有输出都从流中重定向,并传递以写入文件。 当你执行:
Write-Host "Some Text" *>out.txt
您看不到任何 output 并且它都被重定向到该文件。
关键提示:重定向是逐行(简化)工作的,因为重定向是通过一次一行地写入文件来工作的。
同样,当您使用Tee-Object
时,所有输出都从 stream 重定向到管道。 这将传递给 cmdlet Tee-Object
。 Tee-Object
接受输入,然后将该输入写入您想要的变量/文件和屏幕。 这发生在收集和处理输入之后。
这意味着重定向和Tee-Object
命令都是逐行工作的。 重定向和Tee-Object
命令都以这种方式工作是有道理的,因为在尝试编辑和维护打开的文件的同时,很难处理诸如删除字符、四处移动和动态编辑文本之类的事情。 一旦语句完成,它仅设计为单向,output。
在这种情况下,交互运行时, password:
提示符会写入屏幕,您可以响应。
重定向/发球 output 时, password:
文本提示被重定向并缓冲,等待您的响应。 这是有道理的,因为该语句尚未完成。 您不想发送半个可能更改的语句,或者半个 object 沿着管道发送。 只有在您完成语句(例如输入密码 + 回车)之后,整个语句才会沿流/管道传递。 发送整个语句后,它会被重定向/输出 Tee'd 并可以显示。
@Bill_Stewart 是正确的,因为您应该选择交互式提示或全自动解决方案。
编辑:从评论中添加更多信息。
如果我们使用Tee-Object
,它依赖于 Pipeline。 管道只能将完整的对象传递到管道中(例如,完整的字符串,包括新线)。 管道必须与ForEach-Object
或Select-Object
等其他命令交互,并且它们无法处理将不完整的数据传递给它们。 这就是PowerShell 控制台的工作原理,您无法更改它。
同样,重定向是逐行进行的。 背后的原因,我稍后会解释为什么。
所以,如果你想逐个字符地与它交互,那么你正在处理流。 如果你想直接处理流,它会复杂100倍,因为你不能使用PowerShell控制台的便利,你必须直接手动运行进程并自己处理所有输入和output。
首先,您必须手动启动该过程。 为此,我们使用System.Diagnostics.Process class。 伪代码看起来像这样:
$p = [System.Diagnostics.Process]::New()
$p.StartInfo.RedirectStandardOutput = $true
$p.StartInfo.RedirectStandardError = $true
$p.StartInfo.RedirectStandardInput = $true
$p.StartInfo.UseShellExecute = $false
#$p.StartInfo.CreateNoWindow = $true
$p.StartInfo.FileName = "plink.exe"
$p.StartInfo.Arguments = 'root@10.0.0.141 -pw "password" -t -batch "isi auth users create testuser --set-password"'
$p.EnableRaisingEvents = $true
....
我们基本上创建了流程,指定我们将重定向标准输出( StartInfo.RedirectStandardOutput = $true
)以及标准输入到其他东西以供我们处理。 我们如何知道何时读取数据? 好吧,class 有Process.OutputDataReceived 事件。 您绑定到此事件以读取附加数据。 但:
OutputDataReceived 事件表明相关进程已将一行以换行符结尾,写入其重定向的 StandardOutput stream。
因此,即使是过程 class 也围绕流数据的换行符展开。 这就是为什么甚至重定向*>
逐行工作的原因。 PowerShell、cmd等都以进程class为基础运行进程。 它们都绑定到相同的事件和方法来进行处理。 因此,为什么一切都围绕换行符和语句完成。
(大口喘气)所以。 您仍然想一次一个角色以交互方式处理事物吗? 那么你不能使用事件的便利。 您将不得不回退到使用 Stream 阅读器并直接绑定到Process.StandardOutput 属性。 不幸的是,这就是我停下来的地方,并说要实现这一点超出了 SO 的 scope,并且需要更多的研究才能完成。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.