管道脚本时如何使用多行命令,例如 here-strings?

How to use mutli-line commands such as here-strings when piping a script?

在使用 PowerShell 可执行文件的 -Command - 选项时,我遇到了以下限制:

Write-Host "SETUP"
Set-PSDebug -Trace 2
Write-Host "TEST ONE"
$foo = "BAR"
Write-Host "TEST TWO"
Get-ChildItem
Write-Host "TEST THREE"
$bar = @"
BAZ
"@
Write-Host "DONE"

如果我将之前的内容保存到test.ps1并执行cat .\test.ps1 | powershell -Command -,我得到以下输出:

SETUP
DEBUG:    1+  >>>> Write-Host "TEST ONE"
DEBUG:     ! CALL function '<ScriptBlock>'
TEST ONE
DEBUG:    1+  >>>> $foo = "BAR"
DEBUG:     ! CALL function '<ScriptBlock>'
DEBUG:     ! SET $foo = 'BAR'.
DEBUG:    1+  >>>> Write-Host "TEST TWO"
DEBUG:     ! CALL function '<ScriptBlock>'
TEST TWO
DEBUG:    1+  >>>> Get-ChildItem
DEBUG:     ! CALL function '<ScriptBlock>'


    Directory: C:\empty


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       26/02/2017     15:39            179 test.ps1


DEBUG:    1+  >>>> Write-Host "TEST THREE"
DEBUG:     ! CALL function '<ScriptBlock>'
TEST THREE

如您所见,Write-Host "DONE" 行的输出从未显示。

因此,在逐行评估时,这里的字符串 似乎发生了一些事情。为什么会这样?

而且,更重要的是,有没有办法让 here strings 在这种情况下工作?

注意:以下适用于 Windows PowerShell v5.1.14393.693 和 PowerShell Core v6.0.0-alpha16。

PetSerAl,正如他经常做的那样,在问题的评论中提供了关键指针(后来,通过评论,也提供了最简单的修复):

It seems that the problem is not with here-strings [per se], but with multiline commands [in general].

-Command - 需要 最后一个多行命令[=之后至少有 1 个空行82=] 在输入中正确识别所有命令。

根据定义,here-string 是多行命令的一个实例,这就是您遇到此问题的原因。

因此,要解决包含多行命令的脚本中的问题,请在末尾插入一个空行:

Write-Host "SETUP"
Set-PSDebug -Trace 2
Write-Host "TEST ONE"
$foo = "BAR"
Write-Host "TEST TWO"
Get-ChildItem
Write-Host "TEST THREE"
$bar = @"
BAZ
"@
Write-Host "DONE"  # IMPORTANT: Note the empty line below.
 

为什么这是必要的?

答案可以在 powershell 自己的 CLI 帮助 (powershell -?) 中找到,其 -Command 参数的描述 开头为(重点添加):

Executes the specified commands (and any parameters) as though they were typed at the Windows PowerShell command prompt

没有加载PSReadLine模块,当你键入多行命令时交互,你需要一个extra Enter键来提交条目,这样才能让PowerShell 知道您何时输入完命令。

注意:PSReadLine 模块成为 interactive PowerShell 会话的标准部分 W10/PSv5,谢天谢地 避免了这个额外击键的需要,因为它从输入内容的语法推断命令是否完整。
但是,当您通过 -Command -.
传递命令时,PSReadLine 不涉及 如果你想体验PowerShell本身如何在交互式会话中解析多行命令,请先执行Remove-Module PSReadLine

不幸的是,当 -Command - 用于通过 stdin 提供命令时,应用相同的逻辑,所以 你必须模拟额外的 Enter 输入 空行 ,尽管 PetSerAl 发现 [= =47=]单空行最后就够了


如果您希望看到此行为发生变化 and/or 需要对 -File - 的适当支持以将输入视为 脚本 ,请考虑将您的在 GitHub issue #3223.

中听到的声音