【问题标题】:Powershell: Recursively Move Files From Source Directory To One-Level UpPowershell:递归地将文件从源目录移动到上一级
【发布时间】:2020-10-07 17:37:31
【问题描述】:

我刚刚开始涉足 Powershell 并且在搜索了许多脚本之后, 我还没有找到一个有效的。 (可能是我运行不正确,但我启用了正确的管理权限等)

我的要求:
一个Powershell脚本
- 递归遍历目录结构,直到最后一级
- 将所有内容(具有任何扩展名的文件)从文件所在的位置上移一级
- 移动后,删除文件从中移动的文件夹

◘ 之前 ◘ 古典 ├─莫扎特-5 │ └─莫扎特-欧洲作曲家 │ ├─01-交响乐.mp3 │ └─03-symphony.mp3 │ ├─Bach-7 │ └─巴赫 │ ├─02-symphony.ogg │ └─04-音乐会.wav │ │ └─维瓦尔第2号 └─Vivaldi-Not-The-Browser ├─01-track.m4a └─02-solo.mp4 ================================================= ◘ 之后 ◘ 古典 ├─莫扎特-5 │ ├─01-交响乐.mp3 │ └─03-symphony.mp3 │ ├─Bach-7 │ ├─02-symphony.ogg │ └─04-音乐会.wav │ └─维瓦尔第2号 ├─01-track.m4a └─02-solo.mp4



备注:
- 基本文件夹可以称为任何文件夹,例如古典、摇滚等
(因此,理想情况下,我会从所有子文件夹所在的基本文件夹中运行 Powershell 脚本)
- 文件夹深度可以是 1 级或多级深度
( 99.9% 的情况下,它将是 2-3 级深度,即
Root - Music
1st - _Classical_
2nd - Mozart-5
3rd - Mozart-European-Composers

1st - _Indian Classical_
2nd - Ravi
3rd - Ravi Masterpieces
2nd - Zakir
3rd - Zakir-Solo-Piece)


【问题讨论】:

  • 当您获得带有Get-ChildItem 的文件对象列表时,每个对象都有一个.Directory 属性,即当前目录。该道具将有一个.Parent 道具,它是文件所在的父目录。您可以将其用作“移动到”目的地。 [咧嘴]

标签: powershell parent file-move


【解决方案1】:

好吧,这让我走了一段时间,但我终于弄明白了。它需要一个递归函数(一个调用自身的函数)。此方法不关心您的树有多深,因此它可以处理 0.1% 的深度超过 3 层的案例。

Clear-Host

Function Check-Dir {

  Param (
    [Parameter(Mandatory=$True)]
      [String] $Path
  )

  $GCIArgs = @{Path = "$Path"}

  $Files = Get-ChildItem @GCIArgs | 
             Where-Object {-not $_.PSIsContainer}

#--- If no Subs returns $Null! ---
  $Subs  = Get-childitem @GCIArgs | 
             Where-Object {$_.PSIsContainer}

  If ($Null -ne $Subs) {
    ForEach ($S in $Subs) {
      $Bottom = $False
      $DelDir = Check-Dir -Path "$($S.FullName)"
      If ($DelDir) { 
        $S | Remove-Item -Force 
      }
    }
  }

  Else {
   $MIArgs = @{Destination = "$("$Path" + "\..")"
               Force       = $True}
   $Files | Move-Item @MIArgs
   $Bottom = $True         
  }

  If ($Bottom) {$True}
  Else         {$False}

} #End Function Check-Dir

#-------------- Main Program -----------------

$BaseDir = "G:\Test\Music"

Check-dir -path "$BaseDir"

HTH

【讨论】:

  • 仅供参考:我发现您可以通过将 Get-ChildItem 更改为 Get-Item 并将 $GCIArgs = @{Path = "$Path"} 调整为 $GCIArgs 来提高上述程序的效率= @{Path = "$Path"*}。 Get-Item 返回的信息少得多,但仍具有所需的信息。
  • 这实际上还不错:-) 它起作用了,除了:我遇到了一个小错误,...需要指定有关“递归”参数的内容,所以我对该错误消息说“是”,它工作。 KIND OF :-) 对于名为“ 01-[0009]-23\xyz*.* ”的文件夹,您的脚本删除了所有内容,所以我只剩下“ 01-[0009 ]-23 "(即 \\xyz 和 xyz\*.* 已完全删除)。看,我在顶部提到的带有“方括号”的文件夹的 GCI 有一点很有趣。
  • 抱歉,解决这个问题需要比我聪明的人。不知道为什么 [ 字符会犯规,但我找不到将其过滤掉并且仍然使递归正常工作的方法。该程序确实在通常命名的目录上正常工作。我记得过去我们被告诫不要在文件规范的任何部分使用特殊字符。现在我知道为什么了!
  • 在这里查看@Alexander Groß 的评论——stackoverflow.com/questions/1575493/…——关于包含[] 的文件夹的解决方案。该解决方案使我无法理解,因为我是 Powershell 的新手(但不是计算机)。否则,这可以用 RegEx(正则表达式)解决:-)
【解决方案2】:

我能够混合'n'match 一个解决方案,这对我有用,即。
两步流程:
1) 将所有文件向上移动 1 级,到其父级
2) 由于源文件夹现在是空的,因为文件被向上移动了 1 级,所以下一个任务是递归删除所有空文件夹

考虑到这一点:

Get-ChildItem '*\*\*' | Move-Item -Destination { $_.Directory.Parent.FullName }
Get-ChildItem -recurse | Where {$_.PSIsContainer -and `
@(Get-ChildItem -Lit $_.Fullname -r | Where {!$_.PSIsContainer}).Length -eq 0} |
Remove-Item -recurse

注意事项:
○ 我还应该提到我的文件夹名称包含“[”和“]”,这对 Powershell 来说变得具有挑战性,因为 Get-ChildItem 不起作用。
见这里:Option -recurse sometimes does not work for PowerShell cmdlet get-childitem

○ 另外,由于我的文件夹名称中有“[”和“]”,删除这些文件夹也需要一些“技巧”。
起初,我选择了这个解决方案
- How to recursively remove all empty folders in PowerShell?
但是,这个是一个运行良好的:
How to delete empty subfolders with PowerShell?
(灵感来自:PowerShell script to recursively delete empty folders

【讨论】:

    【解决方案3】:

    这在我的测试中有效。

    Clear-Host
    
    $BaseDir = "G:\Test\America"
    
    $GCIArgs = @{Path    = "$BaseDir"
                 Exclude = "*.ini"
                 Recurse = $True}
    $Files = Get-childitem @GCIArgs
    $Files | Where-Object {-not $_.PSIsContainer} |
             Move-Item     -Destination "$BaseDir" 
    
    $Files | Where-Object {$_.PSIsContainer} |
             Remove-Item -Force -Recurse
    

    注意:如果要保存 .ini 文件,可以去掉 Exclude 参数。

    HTH

    【讨论】:

    • 我有 3 个文件夹 [A, B, C],在每个文件夹 [A,B,C] 中,我还有另一个文件夹 [A2, B2, C2]。您的脚本@RetiredGeek,刚刚将所有文件移动到根目录,然后删除了所有文件夹(A\A2、B\B2、C\C2)。我期待 A\A2*.* 中的所有文件移动到 A*.* 并删除 A2。
    • 对不起,我误会了。
    猜你喜欢
    • 2013-04-05
    • 2015-03-01
    • 1970-01-01
    • 2014-11-07
    • 2013-08-20
    • 2013-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多