Powershell,重命名项目无法按预期工作 [英] Powershell, rename-item doesn't work as expected

查看:47
本文介绍了Powershell,重命名项目无法按预期工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

0001-rand01_012.jpg0002-rand03_034.jpg

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

rand01_012.jpg

等等.

我使用以下命令:

Get-ChildItem |Rename-Item -NewName {$_.name.Substring(5)}

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

在目标项目:C:\Users\xxxx\Documents\xx xx\temp2\0123-rand16_030.jpg 目标:C:\Users\"上执行重命名文件"操作xxxx\Documents\xx xx\temp2\rand16_030.jpg".

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

Rename-Item:参数NewName"的脚本块输入失败.使用1"参数调用Substring"的异常:startIndex 不能是大于字符串的长度.

接着是一大堆:

Rename-Item :当该文件已存在时无法创建该文件.

文件本身被重命名,删除了随机数量的字符,而不是预期的 5 个.所以他们的结局是:

01.jpg01.jpg...d14_001.jpg

我过去曾成功使用此命令重命名此类文件.我得到如此随机的结果这一事实让我不得不拔掉头发.

解决方案

tl;dr

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

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

-WhatIf 通用参数在上面的命令中预览操作.一旦您确定操作会执行您想要的操作,请删除 -WhatIf.
PowerShell [Core] 6+ 中,将 (...) 放在 Get-ChildItem 周围不再技术上必要,但建议.[1]

那样:

  • 您预先排除了不相关的文件.

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

    • 出现问题的最可能原因是超过 1 个输入文件在删除第 5 个字符后导致 相同 文件名.
<小时>

听起来好像您错误地重复运行了命令,所以您已经截断了 5 个字符.多次:

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

一旦文件名少于 5 个字符,您将得到与 startIndex 相关的错误,因为 [string] 类的 .Substring() 方法不接受超出字符串长度的索引(尝试 'ab'.Substring(3)).

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

当该文件已经存在时无法创建文件. 错误只是由通常返回新名称的脚本块导致的后续错误,有效地返回空字符串,所以 Rename-Item 有点晦涩地抱怨您无法将文件重命名为其当前名称.

也就是说,在第一次运行期间,您甚至会遇到Cannot create a file when that file already exists 错误,即如果超过 1 个输入文件与它的前 5 个字符.截断后的文件名相同.

例如,0001-rand01_012.jpg0002-rand01_012.jpg 都将重命名为 rand01_012.jpg重命名第一个后失败.

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

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

设置:

# 创建并更改为临时目录.设置位置 (mkdir temp)# 创建名为 0001-rand01_01.jpg, 0002-rand01_02.jpg, ...# 注意前 5 个字符后的后缀.必须是*独特的*.1..9 |%{ $null >"000${_}-rand01_0${_}.jpg" }

第一次运行:

# 没有错误>(Get-ChildItem -File) |Rename-Item -NewName { $_.Name.Substring(5) }# 显示新名称>获取子项 |选择名称名称----rand01_01.jpgrand01_02.jpgrand01_03.jpgrand01_04.jpgrand01_05.jpgrand01_06.jpgrand01_07.jpgrand01_08.jpgrand01_09.jpg

第二次运行产生:

名称----1_01.jpg1_02.jpg1_03.jpg1_04.jpg1_05.jpg1_06.jpg1_07.jpg1_08.jpg1_09.jpg

在第 3 次运行时,所有名称都太短,您将得到的只是 Rename-Item:当该文件已存在时无法创建文件. 错误.><小时>

[1] 在 (...) 中包含 Get-ChildItem 确保匹配的文件收集在 array 中,预先,在调用 Rename-Item 之前.
这明确地防止已重命名的文件被 Get-ChildItem 重新枚举,从而干扰迭代.(...) 的显式使用技术上在 PowerShell [Core] 6+ 中不再需要(Windows 中是必要的)PowerShell (5.1-)),因为 Get-ChildItem 是以 总是在内部收集有关所有前端文件的信息em>,跨平台,因为它按名称对它们进行排序,这本质上只有在收集了所有名称后才有可能.
有鉴于此,您是否使用 (...) 应该在功能上 等同,尽管使用 (...)是可取的,因为它不依赖于实现细节(文档 没有提到输出是如何排序的).

I have a bunch of jpg image files named in the following pattern:

0001-rand01_012.jpg
0002-rand03_034.jpg

I want to rename them by removing the first 5 characters to get the form:

rand01_012.jpg

etc..

I use the following command:

Get-ChildItem | Rename-Item -NewName {$_.name.Substring(5)}

When using this with -whatif flag i get the expected message saying:

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".

But removing the whatif gives me errors of this type:

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.

followed by a whole bunch of:

Rename-Item : Cannot create a file when that file already exists.

The files themselves are renamed with random number of characters removed rather than 5 as was intended. So they have ended up like:

01.jpg
01.jpg
.
.
.
d14_001.jpg

etc.

I have used this command to rename such files in the past with success. The fact that I'm getting such random results is making me pull my hair out.

解决方案

tl;dr

Make sure you only process the files of interest:

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

The -WhatIf common parameter in the command above previews the operation. Remove -WhatIf once you're sure the operation will do what you want.
In PowerShell [Core] 6+, placing (...) around Get-ChildItem is no longer technically necessary, but advisable.[1]

That way:

  • You rule out unrelated files up front.

  • Even if something goes wrong, you can correct the problem and run the command again to reprocess only the failed files, without affecting the previously renamed files.

    • The most likely reason for something going wrong is more than 1 input file resulting in the same filename after removing the 5 first char.

It sounds like you've mistakenly run the command repeatedly, so you've cut off 5 chars. multiple times:

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

Once a filename has fewer than 5 chars., you'll get the the startIndex-related error, because the [string] class's .Substring() method doesn't accept an index beyond the length of the string (try 'ab'.Substring(3)).

That said, since you're running Get-ChildItem without a filter and therefore return all (non-hidden) child items, you may be processing unrelated files ore even directories whose names are too short.

The Cannot create a file when that file already exists. errors are just follow-on errors that result from the script block that normally returns the new name effectively returning the empty string, so Rename-Item is somewhat obscurely complaining that you can't rename a file to its current name.

That said, you can even get Cannot create a file when that file already exists errors during the first run, namely if more than 1 input file with its first 5 chars. chopped off results in the same filename.

E.g., 0001-rand01_012.jpg and 0002-rand01_012.jpg would both be renamed to rand01_012.jpg, which fails once the first one has been renamed.

That is, for your command to work as intended, all filenames that result from dropping the first 5 chars. must be unique.

Here's an MCVE (Minimal, Complete, and Verifiable Example):

Setup:

# 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" }

1st run:

# 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

A 2nd run yields:

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

At the time of the 3rd run, all the names are too short, and all you'll get is Rename-Item : Cannot create a file when that file already exists. errors.


[1] Enclosing Get-ChildItem in (...) ensures that the matching files are collected in an array, up front, before Rename-Item is invoked.
This explicitly prevents already-renamed files from getting re-enumerated by Get-ChildItem and thus interfering with the iteration. Explicit use of (...) is technically no longer necessary in PowerShell [Core] 6+ (it is necessary in Windows PowerShell (5.1-)), because Get-ChildItem is implemented in a way that always internally collects info about all files up front, across platforms, because it sorts them by name, which is inherently only possible after all names have been collected.
In light of that, whether you use (...) or not should functionally amount to the same, although using (...) is advisable, because it doesn't rely on what amounts to an implementation detail (the documentation doesn't mention how the outputs are ordered).

这篇关于Powershell,重命名项目无法按预期工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆