# Read the input file line by line with Get-Content and send each line
# to the ForEach-Object cmdlet, which sees each line as automatic variable
# $_
Get-Content C:\Temp\Name.txt | ForEach-Object {
# Split the line into tokens by whitespace.
# * $firstName receives the 1st token,
# * $lastName the 2nd one (if there were more, $lastName would become an *array*)
$firstName, $lastName = -split $_
# Work with $firstName and $lastName
}
如果您想收集名称对以供以后使用,请考虑将它们包装在自定义对象中,如 DarkLite1's answer。
至于你尝试了什么:
ForEach-Object { -Split $Names }
ForEach ($_ in $SplitNames) {Write-Host 'Name is' $_}
如果您调用ForEach-Object 而不向其提供管道输入,则脚本块将执行一次,因此ForEach-Object { -Split $Names } 实际上与仅调用-Split $Names 相同。
通常,这些陈述表明 PowerShell 的各种枚举结构之间的区别存在混淆。
PowerShell 的各种枚举构造:
有点令人困惑,foreach 也是ForEach-Object 的内置别名。如果您使用foreach,则由解析上下文决定哪个使用构造:在管道中(命令上下文,参数模式),foreach 指的是ForEach-Object cmdlet,否则它指的是foreach 循环(表达式模式) - 参见@987654327 @了解详情。
权衡:在以下情况下使用什么结构:
注意:以下重点关注类似循环的结构,但通常适用对比管道中cmdlet的使用 (流式传输),另一方面,语言语句和基于运算符的表达式/方法调用。[1]
-
性能(执行速度)
-
foreach 循环通常最快,其次是.ForEach() 方法,ForEach-Object cmdlet 最慢(管道通常很慢;见底部)
-
内存效率
- 只有
ForEach-Object cmdlet(管道)提供流式处理处理,其中每个对象在生成时进行处理;除非将整体结果收集在内存中(例如,与输出到文件相反),否则这保持内存使用不变,无论最终处理了多少对象。
-
foreach 和 .ForEach() 要求输入集合完整存在于内存中。
-
输出时机
-
ForEach-Object cmdlet(以及一般的管道)在对象被处理/生成时传递对象,因此您通常会立即开始看到输出。
-
foreach 和 .ForEach(),当直接对命令进行操作时,必须先完整地收集该命令的输出,然后才能开始枚举。
-
语法便利和功能集
-
.ForEach() 方法可以按原样用作表达式的一部分,而使用ForEach-Object 需要包含(...),而使用foreach 循环需要包含@987654389 @
-
.ForEach() 方法提供了允许简洁表达式的附加功能(可以使用 foreach 和 ForEach-Object 模拟功能,但更冗长)
性能对比:
运行以下 性能比较命令,它使用了一个简单的循环体,在我的测试中,foreach 比 .ForEach() 快,ForEach-Object 最慢,正如预期的那样。请注意,代码从this Gist 下载并定义了Time-Command 函数(我可以向您保证这样做是安全的,但您应该始终自己检查源代码):
# Download and define the Time-Command function.
irm https://gist.github.com/mklement0/9e1f13978620b09ab2d15da5535d1b27/raw/Time-Command.ps1 | iex
Write-Verbose -vb "1,000 items, average of 10 runs"
$a=1..1000; Time-Command -Count 10 { foreach($e in $a) { (++$e) } }, { $a.ForEach({ (++$_) }) }, { $a | ForEach-Object { (++$_) } } | Out-Host
Write-Verbose -vb "100,000 items, average of 10 runs"
$a=1..1e5; Time-Command -Count 10 { foreach($e in $a) { (++$e) } }, { $a.ForEach({ (++$_) }) }, { $a | ForEach-Object { (++$_) } } | Out-Host
来自双核 Windows 10 VM 的结果,带有 Windows PowerShell v5.1 / PowerShell Core 7.2.0-preview.6;请注意,绝对数字并不重要,并且会根据许多变量而有所不同,但 ratio(列 Factor)应该会让您有所了解。
Windows PowerShell v5.1:
VERBOSE: 1,000 items, average of 10 runs
Factor Secs (10-run avg.) Command TimeSpan
------ ------------------ ------- --------
1.00 0.001 foreach($e in $a) { (++$e) } 00:00:00.0013639
3.99 0.005 $a.ForEach({ (++$_) }) 00:00:00.0054464
7.46 0.010 $a | ForEach-Object { (++$_) } 00:00:00.0101785
VERBOSE: 100,000 items, average of 10 runs
Factor Secs (10-run avg.) Command TimeSpan
------ ------------------ ------- --------
1.00 0.014 foreach($e in $a) { (++$e) } 00:00:00.0144434
37.56 0.542 $a.ForEach({ (++$_) }) 00:00:00.5424872
62.61 0.904 $a | ForEach-Object { (++$_) } 00:00:00.9043278
PowerShell Core 7.2.0-preview.6:
VERBOSE: 1,000 items, average of 10 runs
Factor Secs (10-run avg.) Command TimeSpan
------ ------------------ ------- --------
1.00 0.001 foreach($e in $a) { (++$e) } 00:00:00.0013071
4.23 0.006 $a.ForEach({ (++$_) }) 00:00:00.0055324
8.04 0.011 $a | ForEach-Object { (++$_) } 00:00:00.0105058
VERBOSE: 100,000 items, average of 10 runs
Factor Secs (10-run avg.) Command TimeSpan
------ ------------------ ------- --------
1.00 0.010 foreach($e in $a) { (++$e) } 00:00:00.0095252
34.12 0.325 $a.ForEach({ (++$_) }) 00:00:00.3250133
57.83 0.551 $a | ForEach-Object { (++$_) } 00:00:00.5508560
注意:在发现原始方法中的缺陷后,上述基准已经更新。新的数字导致不同的结论。
一般观察:
-
foreach 是迄今为止最快的,其次是 .ForEach(),ForEach-Object 是迄今为止最慢的
-
foreach 的性能优势随着迭代次数的增加而增长,并且在大数字时相当可观。然而,与迭代次数无关,.ForEach() 的速度似乎是 ForEach-Object 的两倍。
-
就绝对时间而言,PowerShell Core 的性能似乎优于具有大量迭代次数的 Windows PowerShell。
-
在 macOS 上(结果未在上面显示),减速因素似乎更大,而且绝对执行似乎也更慢。
-
在同一个 PowerShell 会话中重新运行测试会扩大性能差距,这表明只有 foreach 语句才能从按需编译中受益。
[1] 例如,对比使用 cmdlet Get-Content 与使用 语言语句 switch -File 读取文件;或对比使用 cmdlet Where-Object 与通过 method .Where() 或 operator -match 过滤集合。