Weird behaviour in PowerShell bulk file renaming

限于喜欢 提交于 2019-12-05 16:36:59

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)}

Using your preferred aliases:

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

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

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)}

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.

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')}

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.

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)}

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)}

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.

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

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!