ForEach-Object是否对管道中的单个对象或对象集合进行操作?
我很难理解PowerShell管道是如何工作的,我意识到很多问题都是由于ForEach-Object
造成的。在我用过的其他语言中,foreach对集合进行操作,并依次遍历集合中的每个元素。我假设ForEach-Object
在PowerShell管道中使用时,会执行相同的操作。但是,我读到的关于管道的所有信息都表明,集合中的每个元素分别通过管道传递,并且下游的cmdlet被重复调用,分别在每个元素上运行,而不是整个集合。ForEach-Object是否对管道中的单个对象或对象集合进行操作?
因此,ForEach-Object
是对集合中的单个元素进行操作,而不是对集合进行整体操作?用不同的方式来看,管道操作员是否将整个集合传递给ForEach-Object
,然后对其进行迭代,或者管道对象是否迭代集合并将每个元素单独传递给ForEach-Object
?
的ForEach-Object
cmdlet的 - 不像foreach
声明 - 本身执行没有枚举。
相反,它对通过管道传递的每个项目进行操作(在接收第一个项目之前以及在接收到最后一个项目之后,还可以选择执行代码)。
因此,可以说是很差命名,因为它是管道提供枚举(默认),并且ForEach-Object
只是调用对于接收到的每个项的脚本块。
下面的例子说明这一点:
# Let the pipeline enumerate the elements of an array:
> 1, 2 | ForEach-Object { "item: [$_]; count: $($_.Count)" }
item: [1]; count: 1
item: [2]; count: 1
# Send the array *as a whole* through the pipeline (PSv4+)
> Write-Output -NoEnumerate 1, 2 | ForEach-Object { "item: [$_]; count: $($_.Count)" }
item: [1 2]; count: 2
注意脚本/功能/ cmdlet的可选择他们写入到输出流(管道)的集合是否应该列举或发送作为一个整体(作为一个单一的对象)。
在PowerShell代码(脚本或功能,无论是先进的(小命令状)与否,枚举是默认的,但你可以Write-Output -NoEnumerate
退出;在-NoEnumerate
开关是PSv4介绍,在此之前,你不得不使用$PSCmdlet.WriteObject()
,这是仅适用于先进脚本/功能。
还要注意,在表达嵌入的命令通过在(...)
力枚举包围它:
# Send array as a whole.
> Write-Output -NoEnumerate 1, 2 | Measure-Object
Count: 1
...
# Converting the Write-Output -NoEnumerate command to an expression
# by enclosing it in in (...) forces enumeration
> (Write-Output -NoEnumerate 1, 2) | Measure-Object
Count: 2
...
ForEach-Object
迭代集合中的每个项目。当它完成对当前项目执行的脚本块时,它会沿管道发送到下一个可以立即开始处理的命令(而ForEach-Object
正在处理下一个项目,如果有的话)。
您可以在下面的例子中看到这些内容起作用:
Get-Process | ForEach-Object { Start-Sleep 1; $_ } | Format-Table
的Get-Process
cmdlet获取进程的列表,并立即发送到每一个ForEach-Object
在同一时间。 ForEach-Object
正在等待1秒,然后输出当前的管线元素$_
。这被Format-Table
收到,它将它作为表格输出。您可以看到,它不会等到所有进程都处理完才输出到屏幕。
答案是......两者都有。
支持流水线操作的PowerShell函数(高级函数)流程每个项目单独通过流水线。它还可以定义一个begin
和end
块,它将在流水线阶段只执行一次。换句话说,基本的结构是这样的:
function Do-Stuff {
begin {
write-output "This will be done once, at the beginning"
}
process {
Write-output "This will be done for each item"
}
end {
Write-output "This will be done once, at the end"
}
}
的1..3 | foreach-Object {Do-Stuff $_}
的输出将是:
This will be done once, at the beginning
This will be done for each item
This will be done for each item
This will be done for each item
This will be done once, at the end
由于Do-Stuff
被写入到输出流,如果这之后存在额外的流水线级Foreach-Object
,每个对象输出将依次传递到下一个阶段。如果没有其他阶段或其他任何东西来捕获输出,输出流将被写入控制台。
例如:
$verbosepreference = "continue";
[int]1..3|foreach-object {write-output $_; write-verbose ($_*-1)}|foreach-object {$_*$_;write-verbose $_}
给出以下输出:
1
VERBOSE: 1
VERBOSE: -1
4
VERBOSE: 2
VERBOSE: -2
9
VERBOSE: 3
VERBOSE: -3
-X
输出到最后的冗长流(每个项目),因为输出被传递到下一阶段在之前的管道和foreach-object
脚本块中的下一个语句被执行。
快速拨出:'[INT] 1..3'相同'([INT] 1).. 3',这是因为刚'1..3'相同,假设范围运算符表达式的结果是_always_ a(带有[[int]'元素的'[System.Object []]')数组。不管怎么说,像'1'和'3'这样的数字文字都是'[int]'-type,但即使它们不是,PowerShell也会简单地强制它们;例如“1”,“3”将产生相同的结果。 – mklement0