如何使用以下代码在powershell中批量重命名文件:
$nr=1;Get-ChildItem -Filter *.jpg |
Rename-Item -Newname {"PPPPPPP_{0:d3}.jpg" -f $global:nr++}
其中 PPPPPPP 是包含这些文件的父文件夹的名称。
预期输出:
PPPPPPP_001.jpg
PPPPPPP_002.jpg
PPPPPPP_003.jpg
文件位于 C:\USER\MAIN\BLABLABLA\PPPPPPP 文件夹中。
通过脚本块内的
$_.Directory.Name
获取父目录的名称。
Get-Variable
获取对 调用者作用域中
$nr
序列号变量的引用,因此您可以直接修改其值(通过 .Value
),这比使用作用域修饰符 更可取$global:
(可以添加 -Scope 1
来显式定位 parent 范围,但这并不是绝对必要的,为了简洁起见,将其省略):
$nr = 1
Get-ChildItem -Filter *.jpg | Rename-Item -Newname {
'{0}_{1:d3}.jpg' -f $_.Directory.Name, (Get-Variable nr).Value++
} -WhatIf
-WhatIf
预览重命名操作;一旦您确信该命令将按预期执行,请将其删除。
$script:
范围修饰符 来引用该范围内的变量:$nr = 1
Get-ChildItem -Filter *.jpg | Rename-Item -Newname {
'{0}_{1:d3}.jpg' -f $_.Directory.Name, $script:nr++
} -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 = @{ Value = 1 }
Get-ChildItem -Filter *.jpg | Rename-Item -Newname {
'{0}_{1:d3}.jpg' -f $_.Directory.Name, $nr.Value++
} -WhatIf
以下部分解释了这些技术。
可选阅读:修改延迟绑定脚本块或计算属性中调用者的变量:
您不能在脚本块中直接使用
$nr++
来直接增加序列号的原因是:
延迟绑定脚本块(例如传递给
Rename-Item -NewName
的脚本块)和计算属性中的脚本块在child范围中运行。
块局部变量,该变量在每次迭代中都会超出范围,以便下一次迭代再次看到原始值:
$PSIndex
变量来消除手动维护序列号的需要:请参阅
GitHub问题# 13772.
PS> $nr = 1; 1..2 | Select-Object { '#' + $nr++ }
'#' + $nr++
-------------
#1
#1 # !! the *caller's* $nr was NOT incremented
虽然您可以使用作用域修饰符(例如
$global:
或
$script:
)显式引用父作用域中的变量,但这些是 absolute作用域引用可能无法按预期工作:举个例子:如果您移动代码到脚本中,
$global:nr
不再引用使用$nr = 1
创建的变量。顺便说一句:通常应该避免创建 global 变量,因为它们即使在脚本退出后也会保留在当前会话中。
稳健的方法是使用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
变量。如果您不介意使用辅助。 hashtable,您可以利用哈希表是 .NET 引用类型这一事实,这意味着运行延迟绑定脚本块的子作用域会看到与调用者作用域完全相同的对象,并且因此,修改该对象的 property (条目)会在调用中持续存在:
PS> $nr = @{ Value = 1 }; 1..2 | Select-Object { '#' + $nr.Value++ }
'#' + $nr.Value++
---------------------------
#1
#2 # OK - $nr in the caller's scope was incremented
mklement0的提示而修改。
要获取父名称,请使用 .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".
$nr=1;Get-ChildItem -Filter *.jpg |
Rename-Item -Newname {"$(split-path -leaf $_.Directory)_{0:d3}.jpg" -f
$global:nr++}