自动批量重命名文件根据公式包括父文件夹名称使用PowerShell

zf2sa74q  于 2023-11-18  发布在  Shell
关注(0)|答案(3)|浏览(202)

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

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

字符串
其中PPPPPPP是包含这些文件的父文件夹的名称。
预期输出:

  1. PPPPPPP_001.jpg
  2. PPPPPPP_002.jpg
  3. PPPPPPP_003.jpg


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

uz75evzq

uz75evzq1#

  • 通过脚本块中的$_.Directory.Name获取父目录的名称。
  • 使用Get-Variable在 *caller的 * 作用域中获取对$nr序列号变量的引用,这样你就可以直接修改它的值(通过.Value),这比使用作用域修饰符$global:更好(-Scope 1可以被添加以显式地指向 parent 作用域,但它不是绝对必要的,为了简洁起见被省略了):
  1. $nr = 1
  2. Get-ChildItem -Filter *.jpg | Rename-Item -Newname {
  3. '{0}_{1:d3}.jpg' -f $_.Directory.Name, (Get-Variable nr).Value++
  4. } -WhatIf

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

  • 如果您的命令在脚本文件的顶级作用域中运行,一个实用的快捷方式是使用$script:作用域修饰符来引用该作用域中的变量:
  1. $nr = 1
  2. Get-ChildItem -Filter *.jpg | Rename-Item -Newname {
  3. '{0}_{1:d3}.jpg' -f $_.Directory.Name, $script:nr++
  4. } -WhatIf

  • 一个与作用域无关的替代方法也同样简洁,但更晦涩难懂,那就是将$nr变量转换为[ref],这样就可以直接在调用者的作用域中修改它的值(通过.Value)。
  1. $nr = 1
  2. Get-ChildItem -Filter *.jpg | Rename-Item -Newname {
  3. '{0}_{1:d3}.jpg' -f $_.Directory.Name, ([ref] $nr).Value++
  4. } -WhatIf

  • 最后,另一种替代方法是使用aux. hashtable
  1. $nr = @{ Value = 1 }
  2. Get-ChildItem -Filter *.jpg | Rename-Item -Newname {
  3. '{0}_{1:d3}.jpg' -f $_.Directory.Name, $nr.Value++
  4. } -WhatIf


下一节将解释这些技术。

可选阅读:在delay-bind脚本块或计算属性中修改调用方变量:

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

  • Delay-bind script blocks(例如传递给Rename-Item -NewName的)和calculated properties中的脚本块在 * 子 * 作用域**中运行。
  • 将此与传递给Where-ObjectForEach-Object的脚本块进行对比,这些脚本块直接在调用者的作用域中运行。

它是unclear whether that difference in behavior is intentional

  • 因此,尝试修改调用者的变量反而会创建一个 block 局部变量,该变量在每次迭代中都会超出作用域,以便下一次迭代再次看到原始值:
  • 顺便说一句:未来的一个增强建议将通过引入一个 automatic$PSIndex变量来消除手动维护序列号的需要,该变量反映了当前管道对象的序列号:参见GitHub issue #13772

以计算属性为例:

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


虽然可以使用作用域修饰符(如$global:$script:)显式引用父作用域中的变量,但这些是 * 绝对 * 作用域引用,可能无法按预期工作:举个例子:如果将代码移动到脚本中,$global:nr不再引用使用$nr = 1创建的变量。
快速旁白:创建 global 变量通常应该避免,因为它们在当前会话中徘徊,即使在脚本退出后也是如此。

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

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


虽然这种技术是健壮的,但小程序调用会引入开销(尽管这在实践中可能并不重要),而且它有点冗长,但是:

  • 为了简洁,你可以省略-Scope参数。
  • 或者,您可以通过以下方式提高效率:
  1. $nr = 0; $nrVar = Get-Variable nr
  2. 1..2 | Select-Object { '#' + ++$nrVar.Value }


您可以使用**$script:作用域修饰符**来引用脚本文件顶级作用域中的变量,这是直接在该作用域中运行的命令的实用快捷方式:

  1. $nr = 0; 1..2 | Select-Object { '#' + ++$script:nr }


使用**[ref]类型提供了一个更简洁的与作用域无关的替代方案**,尽管这个解决方案有点 * 晦涩 *:

  1. $nr = 0; 1..2 | Select-Object { '#' + ++([ref] $nr).Value }


将变量转换为[ref]返回一个对象,该对象的.Value属性可以访问和修改该变量的值。请注意,由于$nr在此时没有被 * 赋值给 *,因此实际上引用的是 * 调用者的 * $nr变量。
如果你不介意使用一个aux. hashtable,你可以利用哈希表是一个.NET * 引用类型 * 的事实,这意味着延迟绑定脚本块运行的子作用域看到的是与调用者作用域相同的对象,因此修改这个对象的 * 属性 *(条目)在调用中持续存在:

  1. $nr = @{ Value = 0 }; 1..2 | Select-Object { '#' + ++$nr.Value }

展开查看全部
nfg76nw0

nfg76nw02#

EDIT:由于mklement0的提示而修改。

要获取父名称,请使用.Directory.Name作为格式操作符的另一个参数

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

字符串
如果输出看起来正常,则删除-WhatIf
这只会在没有重叠的范围进行重命名时起作用,在这种情况下,您应该使用临时扩展名。
在我的德语区域设置Windows上的示例输出

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

展开查看全部
deikduxw

deikduxw3#

另一种稍微不同的方式:

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

字符串

相关问题