Mathias R. Jessen 在对该问题的评论中提供了关键指针:
foreach迭代变量是$line,但尝试使用$_,但未定义 ($null) 在循环体内。
因此,将$_ 替换为$line 可以解决问题:
$csv = Import-Csv c:\export.csv
Foreach ($line in $csv){
$inc = $i++
mkdir $inc
# $line is the iteration variable, not $_
Copy-Item -Path $line.FileLocation -destination c:\users\bford.$inc -Recurse
}
自动变量 $_(又名$PSItem)仅由 PowerShell 在特定上下文中定义,例如在 管道 中,可用于传递给ForEach-Object cmdlet.
尽管ForEach-Object cmdlet 不幸命名为foreach alias,但它与foreach 语句不同:前者可以 - 仅 - 使用$_ ($PSItem),而后者必须使用选择的任何迭代变量(例如,在上面的例子中,$line)。
在 foreach 语句和 ForEach-Object cmdlet 之间进行选择归结为性能与内存使用:
因此,与您的解决方案相比,速度较慢但内存效率更高且更简洁的等效方案是:
Import-Csv c:\export.csv | ForEach-Object {
mkdir ($inc = $i++); Copy-Item -Path $_.FileLocation -destination c:\users\bford.$inc -Recurse
}
请注意,$i 在应用++ 时会隐式初始化为0,但最好先显式初始化它,您可以在单独的语句中执行此操作事前,或者在传递给ForEach-Object 的-Begin 块中,例如。
可选阅读:统一foreach和ForEach-Object相对于$_
虽然了解foreach 语句 与ForEach-Object cmdlet 的不同用例很重要,但标准化@987654354 的使用还是有价值的@:
issue I've created on GitHub 认为以下应该是可能的 - 但目前(v6 之前)不是:
# WISHFUL THINKING: without an explicit iteration variable, define $_
# implicitly, as with the ForEach-Object *cmdlet*.
foreach ($csv) {
mkdir ($inc = $i++)
Copy-Item -Path $_.FileLocation -destination c:\users\bford.$inc -Recurse
}