管道和 foreach 循环

pipes and foreach loops

最近,我一直在玩 PowerShell,我注意到在使用管道和 foreach 循环时有一些我无法理解的奇怪行为。

这个简单的代码有效:

$x = foreach ($i in gci){$i.length}
$x | measure -max

有道理。

但这段代码不会:

foreach ($i in gci){$i.length} | measure -max

我收到以下错误:

An empty pipe element is not allowed.
At line:1 char:33
+ foreach ($i in gci){$i.length} | <<<<  measure -max
+ CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : EmptyPipeElement

这两种方法有什么区别,为什么第二种会失败?

您需要先评估 foreach,然后像您在第一个测试中那样对结果对象进行管道传输:

$(foreach ($i in gci){$i.length}) | measure -max

或者,使用 % shorthand 在管道之前对其进行评估:

gci | % { $_.Length } | measure -max

foreach 语句不使用管道架构,因此它的输出不能直接传递到管道(即逐项)。为了能够将 foreach 循环的输出传递到管道,您必须 运行 子表达式中的循环:

$(foreach ($item in Get-ChildItem) { $item.Length }) | ...

或者先收集到一个变量中:

$len = foreach ($item in Get-ChildItem) { ... }
$len | ...

如果您想在管道中处理数据,请改用 ForEach-Object cmdlet:

Get-ChildItem | ForEach-Object { $_.Length } | ...

有关 foreach 语句和 ForEach-Object cmdlet 之间差异的进一步解释,请参阅 Master-PowerShell 中的 Scripting Guy blog and the chapter on loops