如何使用Powershell递归重命名文件夹?

10

使用PS进行递归重命名文件很容易(根据Mike Ormond博客的示例进行变化):

dir *_t*.gif -recurse 
    | foreach { move-item -literal $_ $_.Name.Replace("_thumb[1]", "")}

我正在尝试递归重命名文件夹的结构。

使用场景是想要重命名整个VS.NET解决方案(例如从Foo.Bar到Bar.Foo)。为了做到这一点,需要执行以下几个步骤:

  1. 重命名文件夹(例如\Foo.Bar\Foo.Bar.Model => \Bar.Foo\Bar.Foo.Model)
  2. 重命名文件(例如Foo.Bar.Model.csproj => Bar.Foo.Model.csproj)
  3. 在文件中查找和替换以更正名称空间更改(例如'namespace Foo.Bar' =>' namespace Bar.Foo')

我目前正在处理此过程中的第一步。

我发现这篇文章,它谈到了挑战,并声称有解决方案,但没有讨论该解决方案是什么。

我一直遇到递归墙。如果我让PS使用标志处理递归,父文件夹会在子文件夹之前被重命名,脚本会抛出错误。如果我尝试自己实现递归,我的头痛得厉害,事情会变得非常糟糕 - 我无论如何都无法使重命名从递归树的末尾开始。

3个回答

9

以下是rbellamy最终采取的解决方案:

Get-ChildItem $Path -Recurse | %{$_.FullName} |
Sort-Object -Property Length -Descending |
% {
    Write-Host $_
    $Item = Get-Item $_
    $PathRoot = $Item.FullName | Split-Path
    $OldName = $Item.FullName | Split-Path -Leaf
    $NewName = $OldName -replace $OldText, $NewText
    $NewPath = $PathRoot | Join-Path -ChildPath $NewName
    if (!$Item.PSIsContainer -and $Extension -contains $Item.Extension) {
        (Get-Content $Item) | % {
            #Write-Host $_
            $_ -replace $OldText, $NewText
        } | Set-Content $Item
    }
    if ($OldName.Contains($OldText)) {
        Rename-Item -Path $Item.FullName -NewName $NewPath
    }
}

在Get-Items命令中使用-literalPath选项意味着路径或文件名中出现的任何符号都不会被解释。此外,按全名长度排序并不适用于所有情况。如果您有长度差异显著的文件夹,并且较低的路径在较高的路径之前重命名,则脚本将报告找不到文件/文件夹。它的路径已经改变了。 - Jason

3
这样做怎么样 - 递归列出全名列表,按照全名长度降序排序,然后将其重新运行到您的重命名程序中。例如:
gci <directory> -recurse |
 foreach {$_.fullname} |
  sort -length -desc

我喜欢这个。稍微调整一下后,效果很好。 - rbellamy

2
也许这里的某些内容是有用的,下面是一个递归的代码片段,将“pre”添加到目录结构的前面。
$dirs = Get-ChildItem c:/foldertorecurse -rec |  Where-Object {$_.PSIsContainer -eq 1} |  sort fullname -descending
foreach ( $dir in $dirs ) { rename-item -path $dir.fullname -newname ("pre" + $dir.name) } 

你基本上拥有@mjolinir所拥有的,但是你按全名排序,这并没有正确地将排序放在层次结构中的相反顺序。不过还是很好的,谢谢! - rbellamy

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