如何使用 PowerShell 合并/'flatten' 文件夹结构 - 递归

How to merge / 'flatten' a folder structure using PowerShell - recursive

我正在寻求帮助来重组许多子文件夹中的大量文件。

示例来源:

folderX
   aaa.txt
   bbb.txt
folderY
   ccc.txt
   folderZ
      ddd.txt
eee.txt

理想结果:

folderX_aaa.txt
folderX_aaa.txt
folderX_bbb.txt
folderY_ccc.txt
folderY_folderZ_ddd.txt
eee.txt

我希望这是有道理的!我正在使用 Plex 来管理一些媒体,它不喜欢某些用途的子文件夹(例如 featurettes 目录)。

我想使用 PowerShell,因为我已经很熟悉它了 - 但欢迎任何技术或建议。

提前致谢:)

虽然如果你能展示你尝试过的东西会很好,但我很感兴趣...... [grin]

代码的作用...

  • 设置一些常量
  • 创建一些文件和目录以使用
  • 抓取与目标位置和类型匹配的文件
  • 跳过 $TopDir 中已有的任何文件
  • 导出旧文件和目录名称
  • 使用上面的方法创建一个新的完整文件名
  • 移动项目
    这只表明会发生什么。删除 -WhatIf 以真正做到这一点。

请注意,代码不会检查目标中是否存在同名文件。

代码本身...

$TopDir = "$env:TEMP\PlexStuff"
$Delimiter = '_-_'
$Filter = '*.txt'

#region >>> create some files to test with
#   remove this region after you have tested it
@(
    [System.IO.FileInfo]"$TopDir\OneThing\aaa.txt"
    [System.IO.FileInfo]"$TopDir\OneThing\bbb.txt"
    [System.IO.FileInfo]"$TopDir\TwoThing\aaa.txt"
    [System.IO.FileInfo]"$TopDir\ThreeThing\ccc.txt"
    [System.IO.FileInfo]"$TopDir\ThreeThing\ddd.txt"
    [System.IO.FileInfo]"$TopDir\eee.txt"
    ) |
    ForEach-Object {
        # the "$Null =" suppresses unwanted output from the commands
        $Null = mkdir $_.Directory.FullName -Force -ErrorAction SilentlyContinue
        $Null = New-Item -Path $_.Directory.FullName -Name $_.Name -ItemType File -ErrorAction SilentlyContinue
        }
#endregion >>> create some files to test with


$FileList = Get-ChildItem -LiteralPath $TopDir -File -Recurse -Filter $Filter
foreach ($FL_Item in $FileList)
    {
    # skip files that are in the TopDir
    if (-not ($FL_Item.DirectoryName -eq $TopDir))
        {
        $OldFileName = $FL_Item.Name
        $OldDirName = $FL_Item.DirectoryName
        $NewFileName = ($OldDirName, $OldFileName) -join $Delimiter

        Move-Item -LiteralPath $FL_Item.FullName -Destination $NewFileName -WhatIf
        }
    }

输出[为了便于阅读而稍微重新格式化] ...

What if: Performing the operation "Move File" on target "Item: C:\Temp\PlexStuff\OneThing\aaa.txt 
    Destination: C:\Temp\PlexStuff\OneThing_-_aaa.txt".
What if: Performing the operation "Move File" on target "Item: C:\Temp\PlexStuff\OneThing\bbb.txt 
    Destination: C:\Temp\PlexStuff\OneThing_-_bbb.txt".
What if: Performing the operation "Move File" on target "Item: C:\Temp\PlexStuff\ThreeThing\ccc.txt 
    Destination: C:\Temp\PlexStuff\ThreeThing_-_ccc.txt".
What if: Performing the operation "Move File" on target "Item: C:\Temp\PlexStuff\ThreeThing\ddd.txt 
    Destination: C:\Temp\PlexStuff\ThreeThing_-_ddd.txt".
What if: Performing the operation "Move File" on target "Item: C:\Temp\PlexStuff\TwoThing\aaa.txt 
    Destination: C:\Temp\PlexStuff\TwoThing_-_aaa.txt".

这是一个单流水线解决方案:

$targetDir = Convert-Path '.' # Get the current (target) directory's full path.

Get-ChildItem -LiteralPath $targetDir -Directory | # Loop over child dirs.
Get-ChildItem -Recurse -File -Filter *.txt | # Loop over all *.txt files in subtrees of child dirs.
Move-Item -Destination { # Move to target dir.
  # Construct the full target path from the target dir.
  # and the relative sub-path with path separators replaced with "_" chars.
  Join-Path $targetDir `
            ($_.Fullname.Substring($targetDir.Length + 1) -replace '[/\]', '_') 
} -Whatif

-WhatIf 预览移动操作;删除它以执行实际移动。
正则表达式 [/\] 匹配 /\ 作为路径分隔符,从而使解决方案跨平台。