Powershell, элемент переименования не работает должным образом

У меня есть несколько файлов изображений JPG, названных в следующем шаблоне:

0001-rand01_012.jpg
0002-rand03_034.jpg

Я хочу переименовать их, удалив первые 5 символов, чтобы получить форму:

rand01_012.jpg

так далее..

Я использую следующую команду:

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

При использовании этого с флагом -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".

Но удаляя 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.

сопровождаемый целой связкой:

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

Сами файлы переименовываются с удалением случайного числа символов, а не 5, как предполагалось. Таким образом, они в конечном итоге, как:

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

и т.п.

Я использовал эту команду для успешного переименования таких файлов в прошлом. Тот факт, что я получаю такие случайные результаты, заставляет меня вырывать волосы.

1 ответ

Решение

ТЛ; др

Убедитесь, что вы обрабатываете только интересующие вас файлы:

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

размещение (...) вокруг Get-ChildItem не технически необходимо, но желательно. [1]

Сюда:

  • Вы исключаете несвязанные файлы заранее.

  • Даже если что-то пойдет не так, вы можете исправить проблему и снова запустить команду, чтобы обработать только сбойные файлы, не затрагивая ранее переименованные файлы.

    • Наиболее вероятная причина, по которой что-то пошло не так, - более 1 входного файла, приводящего к тому же имени файла после удаления 5 первых символов.

Похоже, вы по ошибке выполнили команду несколько раз, поэтому вы отрезали 5 символов. несколько раз:

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

Если имя файла содержит менее 5 символов, вы получите startIndex ошибка, потому что [string] класса .Substring() метод не принимает индекс за пределами длины строки (попробуйте '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 ошибки во время первого запуска, а именно, если более 1 входного файла с его первыми 5 символами. отрубил результаты в том же имени файла.

Например, 0001-rand01_012.jpg а также 0002-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" }

1-й пробег:

# 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

Второй прогон дает:

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

Во время 3-го запуска все имена слишком короткие, и все, что вы получите, это Rename-Item : Cannot create a file when that file already exists. ошибки.


[1] Вложение Get-ChildItem в (...) гарантирует, что соответствующие файлы собраны в массиве, перед Rename-Item вызывается.
Это явно предотвращает повторное перечисление уже переименованных файлов Get-ChildItem и, таким образом, мешая итерации; явное использование (...) технически не нужно, потому что Get-ChildItem реализован таким образом, что всегда внутренне собирает все файлы заранее, на разных платформах, потому что сортирует их по имени, что по своей сути возможно только после того, как все имена были собраны.
В свете того, используете ли вы (...) или не должны функционально равняться, хотя использование (...) желательно, потому что это не зависит от деталей реализации.

Другие вопросы по тегам