PowerShell 批量文件重命名中的奇怪行为 [英] Weird behaviour in PowerShell bulk file renaming

查看:78
本文介绍了PowerShell 批量文件重命名中的奇怪行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是 PowerShell 的新手,最近我尝试重命名文件夹中的 120 个文件,但遇到了奇怪的行为.

I'm new to PowerShell and recently I try to rename 120 files in a folder and I encounter a weird behavior.

我所拥有的是从 0001.txt、0002.txt、... 0120.txt 命名的文件,总共 120 个文件.我想在每个文件名前添加一个a".我想出了这个命令:

What I have is files with named from 0001.txt, 0002.txt, ... 0120.txt a total of 120 files. I want to add an 'a' in front of each of the file name. I came up with this command:

ls | ren -newname {$_.name -replace '(\d+)','a$1'}

但是在执行之后,我得到了很多这样的错误:

But after execution, I get numerous error like this:

指定的路径、文件名或两者都太长.完全限定的文件名必须小于 260"

"The specified path, file name, or both are too long. The fully qualified file name must be less than 260"

当我查看我的文件夹时,我得到的只是来自

And when I look into my folder, all I get are file names from

aaaaaaaaaaaaaaaaaaaaaaaaa(repeat until it hit system limit on path length)....a0001.txt
...
...
...
aaaaaaaaaaaaaaaaaaaaaaaaa(repeat until it hit system limit on path length)....a0120.txt

使用 -cf 开关进一步检查后,发现 PowerShell 会递归地尝试重命名过程.在重命名所有 120 个文件的第一遍之后,它再次将命令应用于 a0001.txt,有效地在文件名前面添加了另一个a".这样一直持续到它达到路径长度限制并报告错误.

Upon further inspection using the -cf switch, it turns out that PowerShell attempts the renaming process recursively. After the first pass of renaming all the 120 files, it went on again applying the command to a0001.txt effectively adding another 'a' in front of the filename. And this went on until it hit the path length limit and reported the error.

谁能告诉我我的重命名命令有什么问题吗?

Can anyone tell me if there is anything wrong in my renaming command?

推荐答案

管道到 Foreach-Object(简写 %{ })以批量重命名文件.如果您只想在每个文件名前添加字母 a,则不需要正则表达式,您只需:

Pipe to Foreach-Object (shorthand %{ }) to mass-rename files. If you just want to prepend the letter a to each filename, you don't need a regex, all you need to do is this:

Get-ChildItem | %{Rename-Item $_ ('a' + $_.name)}

使用您喜欢的别名:

ls | %{ren $_ ('a' + $_.name)}

要使用正则表达式,使用 ($_.name -replace '^','a') 更简单.如果使用正则表达式的原因是目录中有其他文件,而您只想重命名以数字字符串和 .txt 扩展名命名的文件,请注意您使用的正则表达式会将 a 附加到任何连续数字字符串.例如,agent007.txt 将重命名为 agenta007.txt.你应该让正则表达式只匹配你想要的格式:'^(\d+)\.txt'.

To do it with a regex, it's simpler to do use ($_.name -replace '^','a'). If the reason for using a regex is that you have other files in the directory and you only want to rename files named with a string of digits and the .txt extension, note that the regex you're using would prepend an a to any string of consecutive digits. For example, agent007.txt would be renamed to agenta007.txt. You should have the regex match only the format you want: '^(\d+)\.txt'.

另请注意,通过在 -NewName 参数中使用正则表达式替换,您将每个与正则表达式不匹配的文件重命名为其已有的相同名称.对于 120 个文件来说没什么大不了的,但我会提前过滤文件列表:

Also note that by using a regex replace in the -NewName argument, you're renaming each file that doesn't match the regex to the same name that it already has. Not a big deal for 120 files, but I'd filter the file listing in advance:

Get-ChildItem | ?{$_ -match '^(\d+)\.txt'} | %{Rename-Item $_ ('a' + $_.name)}

<小时>

更新: PowerShell 3.0 中似乎存在一个错误,该错误会导致批量文件重命名在某些情况下失败.如果通过将目录列表传送到 Rename-Item 来重命名文件,则任何重命名为字母顺序高于其当前名称的文件的文件都将以其新名称重新处理,因为它在目录列表中稍后会遇到.这可能会导致重复重命名相同的文件,直到完整路径的长度超过 260 个字符的最大值并引发错误.


UPDATE: There appears to be a bug in PowerShell 3.0 that can cause bulk file renaming to fail under certain conditions. If the files are renamed by piping a directory listing to Rename-Item, any file that's renamed to something that's alphabetically higher than its current name is reprocessed by its new name as it's encountered later in the directory listing. This can cause the same files to be repeatedly renamed until the length of the full path exceeds the 260 character maximum and an error is thrown.

请注意,例如,如果将字母 a 附加而不是前置,则没有问题.这适用于任意数量的文件:

Note, for example, that if the letter a is appended rather then prepended, there is no problem. This works for any number of files:

Get-ChildItem | %{Rename-Item $_ ($_.name + 'a')}

如果文件名为b0001b0002等,并且在前面加上字母a,则不会发生重复的重新处理.但是,如果前面有字母 c,它确实会出现.

If the files are named b0001, b0002, etc., and the letter a is prepended, the repeated reprocessing does not occur. However, if the letter c is prepended, it does occur.

如果所有文件的名称都以 b 开头,则以下命令在任意数量的文件的开头添加一个 a:

The following command adds a single a to the beginning of any number of files if all their names begin with with b:

Get-ChildItem | %{Rename-Item $_ ('a' + $_.name)}

给定名称以 b 开头的相同文件,以下命令重复添加字母 c 直到达到长度限制:

Given the same files, with names beginning with b, the following command prepends the letter c repeatedly until the length limit is reached:

Get-ChildItem | %{Rename-Item $_ ('c' + $_.name)}

这只发生在包含一定数量或更多文件的列表中.OP说他把文件数减少到20以下没有问题.我发现阈值是37(36个文件或更少,重新处理不会发生).我尚未确定所有适用案例的数字是否相同,还是取决于更具体的因素.

This only happens for a listing containing a certain number of files or higher. The OP said that he doesn't have a problem if he reduces the number of files to less than 20. I found that the threshold is 37 (with 36 files or less, the reprocessing doesn't happen). I haven't determined yet whether the number is the same for all applicable cases or depends on more specific factors.

我稍后会详细说明,并在更具体地确定此问题的参数后向 Microsoft 提交错误报告.

I'll elaborate on this later, and submit a bug report to Microsoft once I've determined the parameters of this problem more specifically.

解决方法:使用 Where-Object 过滤 Get-ChildItem 中的列表,以便排除新文件名.更新部分之前的上述命令的最后一个版本适用于 PowerShell 3.0.据推测,重命名的文件以其新名称重新引入管道并再次处理,但因为新名称与过滤器 ?{$_ -match '^(\d+)\.txt' 不匹配},它们不会在第二次通过管道时重命名,也不会再次重新处理.

WORKAROUND: Filter the listing from Get-ChildItem with Where-Object such that the new filenames are excluded. The last version of the command above before the update section works in PowerShell 3.0. Presumably, the renamed files are reintroduced into the pipeline by their new names and processed one more time, but because the new names don't match the filter ?{$_ -match '^(\d+)\.txt'}, they are not renamed on their second pass through the pipeline and not reprocessed again.

这篇关于PowerShell 批量文件重命名中的奇怪行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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