【问题标题】:Converting a batch FOR /F with multiple commands to a FOREACH in PowerShell将具有多个命令的批处理 FOR /F 转换为 PowerShell 中的 FOREACH
【发布时间】:2015-02-18 14:31:48
【问题描述】:

前段时间,@Magoo 很好地帮助我制定了 FOR /F 命令将文件归档到 7-zip:

Using FOR or FORFILES batch command to individually archive specific files

从那以后,我对它进行了一些扩展,并希望用它做更精细的事情。但是,为了让这个问题保持简单,我已经包含了一些基础知识来尝试使其正常工作,但我并没有取得太大的成功。

我对 PowerShell 比较陌生,我有一些特定的理由使用它而不是批处理文件,继续前进。 我了解一些更有经验的用户可能会注意到在 PowerShell 中使用此类语句会降低性能,但这对我来说不是一个重要问题。

$env:Path += ";C:\Program Files\7-Zip"
$sourcedir = read-host "Enter the directory to archive: "
foreach ($aname in {
  'cmd /c dir /s/b /a-d "$sourcedir\*.iso" '
  'cmd /c dir /s/b /a-d "$sourcedir\*.daa" '
  'cmd /c dir /s/b /a-d "$sourcedir\*.nrg" '
  'cmd /c dir /s/b /a-d "$sourcedir\*.flp" '}
  ) {
     IF NOT EXIST $aname.7z (
       echo 7z a -t7z "$aname.7z" "$aname" -mx9 -mmt >> Z:\test\7z-log.txt
       ECHO "$aname" archived.
     ) ELSE (
       ECHO "$aname" archive file already exists.
        )
  }

我在使用 IF EXIST 语句时遇到了一些问题,即使我删除了 IF 并有一个单行 ECHO 只是为了进一步简化它,但我无法让它输出我想要的内容。

所以,我尝试了另一种方法:

$env:Path += ";C:\Program Files\7-Zip"
$sourcedir = read-host "Enter the directory to archive: "
$dir_iso = ForEach-Object { cmd /c dir /s/b /a-d "$sourcedir\*.iso" }
$dir_daa = ForEach-Object { cmd /c dir /s/b /a-d "$sourcedir\*.daa" }
$dir_nrg = ForEach-Object { cmd /c dir /s/b /a-d "$sourcedir\*.nrg" }
$dir_flp = ForEach-Object { cmd /c dir /s/b /a-d "$sourcedir\*.flp" }
foreach ($aname in $dir_iso,$dir_daa,$dir_nrg,$dir_flp) {
       ECHO "$aname" archived.
       }

但这所做的是将每种类型的每个项目聚集在一起,然后将“归档”附加到该集合中。比如:

C:\folder1\iso1.iso C:\folder1\iso2.iso C:\folder1\iso3.iso archived.
C:\folder2\image.nrg archived.
C:\folder3\app1.flp C:\folder3\app2.flp archived.

代替:

C:\folder1\iso1.iso archived.
C:\folder1\iso2.iso archived.
C:\folder1\iso3.iso archived.
C:\folder2\image.nrg archived.
C:\folder3\app1.flp archived.
C:\folder3\app2.flp archived.

我很难让它发挥作用。有人可以帮忙吗?

谢谢。

【问题讨论】:

    标签: windows powershell batch-file for-loop foreach


    【解决方案1】:

    我在这里看到的第一件事是您正在使用它从文件系统中获取文件信息

    $dir_iso = ForEach-Object { cmd /c dir /s/b /a-d "$sourcedir\*.iso" }
    

    更具体地说是cmd /c dir /s/b /a-d "$sourcedir\*.iso"。这很容易转化为Get-ChildItem

    $dir_iso = Get-ChildItem -Path $sourcedir -Filter "*.iso" -Recurse -File | Select-Object -ExpandProperty FullName
    
    • Path 是您正在检查的文件夹的文件路径
    • Filter 你只想要以 .iso 结尾的文件
    • Recurse 检查所有子目录
    • File 仅返回文件而不返回目录(PowerShell 3.0 或更高版本!。如果这是一个问题,有一个简单的等价物。)
    • Select-Object -ExpandProperty FullName 只会返回在数组中找到的文件的完整路径。

    IF EXIST 可以替换为Test-Path

    If(Test-Path "$aname.7z"){
       Do stuff...
    }
    

    至于 ForEach 循环 foreach ($aname in $dir_iso,$dir_daa,$dir_nrg,$dir_flp) 有几个很好的方法,但最简单的转换是

    $dir_iso + $dir_daa + $dir_nrg + $dir_flp | ForEach-Object{
        Do Stuff
    }
    

    我可能会在一个变量中构建文件集合,以避免将数组连接在一起

    $files = Get-ChildItem -Path $sourcedir -Recurse -File | Where-Object{$_.Extension -match "(iso|daa|nrg|flp)$" } | Select-Object -ExpandProperty FullName
    
    $files | ForEach-Object{
        Write-Host "$_"
    }
    

    【讨论】:

      【解决方案2】:

      使用 write-host 而不是 echo。 多维数组,所以你需要一个内循环。

      foreach ($aname in $dir_iso,$dir_daa,$dir_nrg,$dir_flp) {
        foreach ($bname in $aname) {
             write-host "$bname" archived.
        }
      }
      

      【讨论】:

        【解决方案3】:

        另一种可能性;这会将命令连接在一起,而不是将每个命令存储在单独的变量中。

        Get-Item $sourcedir\* | 
        Where {$_.Extension -like ".iso" -or $_.Extension -like ".daa" -or $_.Extension -like ".nrg" -or $_.Extension -like ".flp"} | 
        Foreach-Object {
            if (-Not (Test-Path "$_.BaseName.7z")) 
            { 
                Write-Host $_.FullName not yet archived.
            }
            else
            {
                Write-Host $_.FullName already archived.
            }
        }
        

        【讨论】:

        • 如果你打算这样做,你也可以简单地使用 match。 $_.Extension -match "(iso|daa|nrg|flp)$"。根据文件结构的大小,过滤器的性能可能更好。
        猜你喜欢
        • 2017-07-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-20
        • 2011-10-21
        • 1970-01-01
        相关资源
        最近更新 更多