【问题标题】:Automatically batch renaming files according to a formula including parent folder name using Powershell根据公式自动批量重命名文件,包括使用 Powershell 的父文件夹名称
【发布时间】:2018-11-20 12:26:00
【问题描述】:

如何使用以下代码在 powershell 中批量重命名文件:

$nr=1;Get-ChildItem -Filter *.jpg |
  Rename-Item -Newname {"PPPPPPP_{0:d3}.jpg" -f $global:nr++}

其中 PPPPPP 是包含这些文件的父文件夹的名称。

预期输出:

PPPPPPP_001.jpg
PPPPPPP_002.jpg
PPPPPPP_003.jpg

文件位于 C:\USER\MAIN\BLABLABLA\PPPPPPP 文件夹中。

【问题讨论】:

    标签: powershell batch-rename delay-bind


    【解决方案1】:
    • 通过脚本块内的$_.Directory.Name 获取父目录的名称。

    • 使用Get-Variable调用者的范围内获取对$nr序列号变量的引用,这样你就可以直接修改它的值(通过.Value),这比使用范围修饰符$global:

    $nr = 1
    Get-ChildItem -Filter *.jpg | Rename-Item -Newname {
      '{0}_{1:d3}.jpg' -f $_.Directory.Name, (Get-Variable nr).Value++
    } -WhatIf
    

    -WhatIf预览重命名操作;删除它,一旦您确信该命令将按预期执行。

    • 一种更简洁、更高效(但更模糊)的替代方法是将$nr 变量转换为[ref],以便您可以直接在调用者的范围内修改其值(通过.Value)。
    $nr = 1
    Get-ChildItem -Filter *.jpg | Rename-Item -Newname {
      '{0}_{1:d3}.jpg' -f $_.Directory.Name, ([ref] $nr).Value++
    } -WhatIf
    

    以下部分解释了这些技术。


    可选阅读:在延迟绑定脚本块或计算属性中修改调用者的变量:

    您不能只在脚本块中使用$nr++ 来直接增加序列号的原因是:

    • Delay-bind script blocks(例如传递给Rename-Item -NewName 的那个)和calculated properties 中的脚本块在 范围内运行

    • 因此,尝试修改调用者的变量反而会创建一个 -在每次迭代中超出范围的局部变量,以便下一次迭代再次看到原始变量价值:

    • 顺便说一句:通过引入反映序列号的自动 $PSIndex 变量,提议的未来增强功能将消除手动维护序列号的需要当前管道对象:见GitHub issue #13772

    以计算属性为例:

    PS> $nr = 1; 1..2 | Select-Object { '#' + $nr++ }
    
     '#' + $nr++ 
    -------------
    #1
    #1   # !! the *caller's* $nr was NOT incremented 
    

    虽然您可以使用$global:$script: 等范围修饰符来显式引用父范围中的变量,但这些绝对范围引用可能无法按预期工作:要点:如果将代码移动到脚本中,$global:nr 不再引用使用$nr = 1 创建的变量。

    快速抛开:通常应避免创建 全局 变量,因为它们会在当前会话中徘徊,即使在脚本退出后也是如此。

    稳健的方法是使用Get-Variable -Scope 1 调用来稳健地引用直接父作用域:

    PS> $nr = 1; 1..2 | Select-Object { '#' + (Get-Variable -Scope 1 nr).Value++ }
    
     '#' + (Get-Variable -Scope 1 nr).Value++ 
    ------------------------------------------
    #1
    #2  # OK - $nr in the caller's scope was incremented
    

    虽然这种技术很强大,但 cmdlet 调用会带来开销,而且有点冗长,但是:

    • 为简洁起见,您可以省略 -Scope 参数。

    • 或者,您可以通过以下方式提高效率:

      $nr = 1; $nrVar = Get-Variable nr
      1..2 | Select-Object { '#' + $nrVar.Value++ }
      

    使用 [ref] 类型提供了一个更简洁的替代方案,尽管解决方案有点晦涩

    PS> $nr = 1; 1..2 | Select-Object { '#' + ([ref] $nr).Value++ }
    
     '#' + ([ref] $nr).Value++ 
    ---------------------------
    #1
    #2  # OK - $nr in the caller's scope was incremented
    

    将变量转换为[ref] 会返回一个对象,其.Value 属性可以访问和修改该变量的值。请注意,由于此时$nr 没有被分配给,因此确实是调用者的 $nr 变量被引用。

    【讨论】:

      【解决方案2】:

      编辑:因mklement0s 提示而修改。
      要获取父名称,请使用.Directory.Name 作为格式运算符的另一个参数

      $nr=1
      Get-ChildItem *.jpg -file|
        Rename-Item -Newname {"{0}_{1:d3}.jpg" -f $_.Directory.Name,([ref]$nr).Value++} -whatIf
      

      如果输出看起来正常,请删除 -WhatIf

      这仅在重命名没有重叠范围时才有效,在这种情况下,您应该使用临时扩展名。

      我的德语语言环境 Windows 上的示例输出

      WhatIf: Ausführen des Vorgangs "Datei umbenennen" für das Ziel "Element: A:\test\150.jpg Ziel: A:\test\test_007.jpg".
      WhatIf: Ausführen des Vorgangs "Datei umbenennen" für das Ziel "Element: A:\test\151.jpg Ziel: A:\test\test_008.jpg".
      WhatIf: Ausführen des Vorgangs "Datei umbenennen" für das Ziel "Element: A:\test\152.jpg Ziel: A:\test\test_009.jpg".
      WhatIf: Ausführen des Vorgangs "Datei umbenennen" für das Ziel "Element: A:\test\153.jpg Ziel: A:\test\test_010.jpg".
      WhatIf: Ausführen des Vorgangs "Datei umbenennen" für das Ziel "Element: A:\test\154.jpg Ziel: A:\test\test_011.jpg".
      WhatIf: Ausführen des Vorgangs "Datei umbenennen" für das Ziel "Element: A:\test\155.jpg Ziel: A:\test\test_012.jpg".
      

      【讨论】:

        【解决方案3】:

        另一种略有不同的方式:

        $nr=1;Get-ChildItem -Filter *.jpg |
        Rename-Item -Newname {"$(split-path -leaf $_.Directory)_{0:d3}.jpg" -f
        $global:nr++}
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-07-14
          • 2022-01-15
          • 2014-08-10
          • 1970-01-01
          相关资源
          最近更新 更多