繁体   English   中英

我可以在 Powershell 中打开无缓冲程序 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-ObjectSelect-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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM