PowerShell中的ForEach $file in $Files

27

我有一个PowerShell脚本,获取文件列表并移动符合特定条件的文件。为什么即使对象为空,foreach循环也会运行?

我原以为如果$i不存在,它就不会运行。但是,如果$filePath中没有结果,为什么forEach循环还会运行一次?我已经解决了我的问题,但我很好奇,尝试搜索,但找不到答案。

为了让这个脚本正常工作,我只需在进入forEach循环之前检查$filePath是否存在。

例如,if ($filePath){...

 $filePath = Get-ChildItem -Path $sourceDir | Where-Object {! $_.PSIsContainer -AND ($_.Name -Match "^XXX_XXX*" -OR $_.Name -Match "^YYY_XX*")}

 ForEach($i in $filePath){
     $sfName =  $i.Name
     $sfDir = $i.Directory
     $tFileName = testFile $destDir $sfName
     $sFile = $sourceDir + $sfName
     $tFile = $destDir + $tFileName

     moveFile $sFile $tFile
1个回答

63

这是一个经典问题,在PowerShell V3中已经得到了解决。 PowerShell的foreach循环允许您迭代标量值,例如:

foreach ($i in 1) {$i}

这很方便,因为你迭代的集合可能包含 0、1 或 N 个项,例如:

$files = Get-ChildItem c:\temp\*.txt
foreach ($file in $files) {$file}
在这种情况下,Get-ChildItem可能会返回0、1或N个文件。N个文件很好,我们可以遍历它们。但是如果它只返回1个文件,然后您必须将那个文件放入数组中以便使用foreach-那就有点糟糕了。所以foreach允许您迭代标量对象。当Get-ChildItem返回0个对象时发生问题。在这种情况下,不会向$files分配空数组。相反,将$null赋值给它。PowerShell认为$null是标量,因此foreach循环将执行一次,其中迭代的值为$null。这就有点糟糕了。我和许多其他人早就告诉过团队这一点,所以在V3中,他们更改了foreach,以便在值为$null时不迭代标量。在V1/V2中解决此问题的另一种方法是确保空情况生成一个空数组而不是$null。您可以使用@()数组表达式来实现这一点。
$files = @(Get-ChildItem c:\temp\*.txt)
foreach ($file in $files) {$file}

这对于0、1和N个文件都适用。当没有文件时,@()将导致一个空数组被赋值给$files。foreach在遍历空数组时不会执行其主体。


谢谢。我通常使用PowerShell v3,但正在为一些旧服务器编写脚本,那些权力机构不想升级。这是那种我确定已经被解答了无数次,但在搜索中很难量化的事情之一。 - Bagger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接