Powershell,重命名项目无法按预期工作

kch*_*hak 2 powershell rename-item-cmdlet

我有一堆以以下模式命名的jpg图像文件:

0001-rand01_012.jpg
0002-rand03_034.jpg
Run Code Online (Sandbox Code Playgroud)

我想通过删除前5个字符来重命名它们以获得表格:

rand01_012.jpg
Run Code Online (Sandbox Code Playgroud)

等等..

我使用以下命令:

Get-ChildItem | Rename-Item -NewName {$_.name.Substring(5)}
Run Code Online (Sandbox Code Playgroud)

当与-whatif标志一起使用时,我得到预期的消息:

Performing the operation "Rename File" on target "Item: C:\Users\xxxx\Documents\xx xx\temp2\0123-rand16_030.jpg Destination: C:\Users\
xxxx\Documents\xx xx\temp2\rand16_030.jpg".
Run Code Online (Sandbox Code Playgroud)

但是删除whatif给我这种类型的错误:

Rename-Item : The input to the script block for parameter 'NewName' failed. Exception calling "Substring" with "1" argument(s): "startIndex cannot be 
larger than length of string.
Run Code Online (Sandbox Code Playgroud)

其次是一堆:

Rename-Item : Cannot create a file when that file already exists.
Run Code Online (Sandbox Code Playgroud)

重命名文件本身时会删除随机数量的字符,而不是按预期的5个字符。所以他们最终像:

01.jpg
01.jpg
.
.
.
d14_001.jpg
Run Code Online (Sandbox Code Playgroud)

等等

过去,我已经使用此命令成功重命名了此类文件。我得到如此随机结果的事实使我拔头发。

mkl*_*nt0 5

tl; dr

确保只处理感兴趣的文件:

(Get-ChildItem -File [0-9][0-9][0-9][0-9]-*.jpg) |
  Rename-Item -NewName {$_.name.Substring(5)}
Run Code Online (Sandbox Code Playgroud)

放置(...)技术上Get-ChildItem不是必需的,但建议这样做。[1]

那样:

  • 您可以排除不相关的文件。

  • 即使出现问题,您也可以纠正问题并再次运行命令以仅处理失败的文件,而不会影响以前重命名的文件。

    • 出现问题的最可能的原因是多个输入字符超过1个,而删除了5个第一个字符后却导致了相同的文件名。

听起来您错误地重复运行了命令,所以您减少了5个字符。多次

0001-rand01_01.jpg-> rand01_01.jpg->_01.jpg

文件名少于5个字符后,您将得到startIndex-related错误,因为[string]类的.Substring()方法不接受超出字符串长度的索引(try 'ab'.Substring(3))。

就是说,由于您Get-ChildItem没有过滤器就在运行,因此返回了所有(非隐藏的)子项,因此您可能正在处理不相关的文件或名称太短的目录

这些Cannot create a file when that file already exists.错误只是脚本错误导致的后续错误,这些脚本通常会正常返回新名称,并有效地返回空字符串,因此Rename-Item,有些晦涩的抱怨是您无法将文件重命名为其当前名称。

就是说,您甚至可能Cannot create a file when that file already exists在第一次运行时出错,即,如果有多个输入文件的前5个字符为1个字符。切掉的文件名相同。

例如,0001-rand01_012.jpg0002-rand01_012.jpg都将重命名为rand01_012.jpg,一旦第一个被重命名,它就会失败

也就是说,为了使您的命令按预期工作,所有文件名都是由于删除前5个字符而产生的。必须是唯一的。

这是一个MCVE(最小,完整和可验证的示例)

设定:

# Create and change to temp dir.
Set-Location (mkdir temp)
# Create sample input files named 0001-rand01_01.jpg, 0002-rand01_02.jpg, ...
# Note how the suffixes after the first 5 char. must be *unique*.
1..9 | %{ $null > "000${_}-rand01_0${_}.jpg" }
Run Code Online (Sandbox Code Playgroud)

第一次运行:

# No errors
> (Get-ChildItem -File) | Rename-Item  -NewName { $_.Name.Substring(5) }
# Show new names
> Get-ChildItem | Select Name

Name         
----         
rand01_01.jpg
rand01_02.jpg
rand01_03.jpg
rand01_04.jpg
rand01_05.jpg
rand01_06.jpg
rand01_07.jpg
rand01_08.jpg
rand01_09.jpg
Run Code Online (Sandbox Code Playgroud)

第二次运行产生:

Name    
----    
1_01.jpg
1_02.jpg
1_03.jpg
1_04.jpg
1_05.jpg
1_06.jpg
1_07.jpg
1_08.jpg
1_09.jpg
Run Code Online (Sandbox Code Playgroud)

在第3次运行时,所有名称都太短,您将得到的只是Rename-Item : Cannot create a file when that file already exists.错误。


[1]围Get-ChildItem(...)确保匹配文件在一个收集阵列前场,前Rename-Item被调用。
这明确地防止了已经重命名的文件被Get-ChildItem迭代重新枚举,从而干扰了迭代。明确使用的(...)在技术上没有必要,因为Get-ChildItem实现在一个方式总是在内部收集的所有文件前面,跨平台的,因为它的名字,所有的名字已被收集之后本质上是唯一可能的排序。
在光,无论您使用(...)与否应功能尽管(...)建议使用,但数量相同,因为它不依赖于实现细节。