【问题标题】:Powershell: unexpected echo in read-hostPowershell:读取主机中的意外回声
【发布时间】:2021-03-10 22:13:32
【问题描述】:

我正在尝试在 powershell 中编写一个简单的文本操作过滤器(W10-64 位上的 5.1)。我的目标是将它用作批处理(.bat)中管道的一部分,例如:

command1.exe | powershell "...my filter..." | command2.exe

我遇到了一个奇怪的问题:“Read-Host”cmdlet 总是回显它的输入。示例:

echo 1234 | powershell "$a=Read-Host"

生产

1234

(注意:请参阅PowerShell: Disable echo in Read-Host)。

如何避免这种意外回声?有没有其他方法可以在 powershell 中读取 STDIN?

注意 2:我知道我可以在 powershell 中完成所有管道工作,但由于许多原因,这不适合我的情况。我想要的是一个“通用过滤器”,适合成为“.bat”中管道的一部分。而且,不,存储中间数据的临时文件不是一种选择。

编辑:正如“Compo”所指出的,MS 文档是这样描述 Read_Host 的:

您不能将输入通过管道传送到此 cmdlet

因此,试图让它发挥作用是没有意义的。

EDIT2:正如“mklement0”所解释的,“[Read_Host] 确实接受管道,即来自外部的标准输入,例如提供给 PowerShell 的 CLI 时”。真正的问题是它旨在简化用户输入,而不是提供对标准输入的通用访问权限。

实际的问题是:有没有其他方法可以在 powershell 中读取 STDIN?

【问题讨论】:

  • 请解释一下 [batch-file] 标签的用途。您的问题明确指出您“正在尝试在 powershell 中编写一个简单的文本操作过滤器”,并且您的目标只是让它成为 .bat 文件管道的一部分。您在哪里输入了问题中显示的命令?
  • 我添加了“批处理文件”标签,因为我的典型用例是批处理文件中的管道。我的示例中的命令来自控制台中的测试,但同样的情况也发生在批处理中。 (但也许我没有抓住重点,抱歉)。
  • ...但是什么控制台?
  • 顺便说一句,如果你看看Read-Host command information,你会清楚地看到它不接受管道输入
  • “你不能通过管道输入这个 cmdlet”...我明白了...(+1 给你)。那么,有没有其他方法可以做到这一点? (顺便说一句:在我的情况下,“控制台”是普通的 cmd.exe 提示符)

标签: powershell batch-file


【解决方案1】:

有没有其他方法可以在 powershell 中读取 STDIN?

这已经发生了,你只需要知道如何挂钩它 - 例如using$input automatic enumerator variable

C:\> echo "camelCase" |powershell -Command "$input |ForEach-Object ToUpper"
CAMELCASE

由于 PowerShell 和 CMD 使用的语法略有不同,并且可能有点难以逃脱,我强烈建议将您的过滤器放在脚本文件中并调用它们:

# myUpperCaseFilter.ps1
$input |ForEach-Object ToUpper
# script.bat
command1.exe |powershell -File path\to\myUpperCaseFilter.ps1 |command2.exe

【讨论】:

  • 这就是我想要的! (顺便说一句,cmd.exe 语法很痛苦,但在某些情况下我无法避免使用它)
【解决方案2】:

此答案补充了 Mathias R. Jessen's helpful answer,它显示了处理通过管道 (stdin) 传递给 PowerShell CLI数据 的正确方法。


Read-Host:

  • 是否接受来自内部PowerShell会话管道输入,这是文档所指的内容。

  • 是否接受管道,即stdin[1]输入来自外部,例如提供给 PowerShell 的 CLI 时。

但是,这有限制

  • 在交互式使用中,Read-Host 只读取一个行。

  • 因为即使使用 stdin 输入也会模拟交互行为,因此输入也总是回显到显示器,这是无法抑制的。

  • 所有其他 cmdlet(以及表达式)不同 - 需要显式使用 $input 才能处理标准输入数据,如 Mathias 的回答 - Read-Host 中所示 隐式读取标准输入。

    • 这意味着您必须要么完全通过Read-Host调用来使用标准输入使用$input将其传递给其他命令.

这仅留下 一个 合法的用例,用于将字符串从 PowerShell 外部管道传输到 Read-Host

  • 为给定命令/脚本的交互式提示提供自动响应;例如:

    C:\>echo y | powershell -c "$response = Read-Host 'Continue (y/n)'; if ($response.Trim() -ne 'y') { exit 2 }; 'continuing...'"
    Continue (y/n): y
    continuing...
    
  • 更多信息请参见this answer


相反,这意味着您不应该使用 Read-Host 在变量中收集标准输入输入,因为只读取了 一个 行并给出了不需要的回显行为。

通常,您只需通过命令内部管道 $input 将 stdin 输入中继到其他命令,如 Mathias 的回答所示; 要预先明确收集变量中的所有标准输入,您可以将$()subexpression operator(或@()array-subexpression operator)应用于$input 枚举器: p>

C:\>(echo abc & echo def) | powershell "$allInput=$($input); \"$($allInput.Count) lines received.\""
2 lines received.

[1] stdin,标准输入流,是一个操作系统级别的概念,标准输出流,stdout em> 和 stderr。相比之下,PowerShell 实现了自己的流系统:6(!) 个输出 流在概念 about_Redirection 主题中进行了描述; success 输出流(编号 1)和 error 流(2)类似于 stdoutstderr ,分别。然而,没有 stdin 类似的模拟:(流)输入到其他命令只提供通过管道(而不是通过< 运算符支持PowerShell 支持的其他 shell)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-03
    • 1970-01-01
    • 1970-01-01
    • 2020-11-10
    相关资源
    最近更新 更多