Переименование файлов PDF в последовательном порядке с помощью powershell

У меня есть большое количество PDF-файлов, которые нужно переименовать в последовательном порядке. Первоначально они были отсканированы в один документ, а затем извлечены в виде отдельных файлов. При извлечении имя становится «444026-444050 1», «444026-444050 2» и т. д. Я пытаюсь переименовать все файлы, чтобы они соответствовали номеру документа («444026-444050 1» станет «444026»).

Я нашел следующую строку кода, которую я могу использовать в Powershell, но кажется, что все, что превышает 9 файлов, является проблемой! Как только я попробовал это с 10 файлами, только первый файл сохраняется правильно. Остальные становятся беспорядочными (в файле 444027 содержится содержимое файла 444035, затем в файле 444028 содержится 444027, а в файле 444029 — 444028 и т. д.)

Я предполагаю, что есть какая-то проблема с петлей, но мне трудно ее исправить.

Кто-нибудь может помочь? Благодарность

Dir *.pdf | ForEach-Object  -begin { $count=26 }  -process { rename-item $_ -NewName "4440$count.pdf"; $count++ }

person 93cd    schedule 11.02.2020    source источник
comment
если 444026-444050 1 станет 444026, то чем станет 444026-444050 2? Как разрешить эти потенциальные дубликаты? Уточните, пожалуйста, непосредственно обновив свой вопрос.   -  person mklement0    schedule 11.02.2020


Ответы (2)


Порядок, в котором Dir (который является псевдонимом Get-ChildItem) извлекает элементы, не является строго гарантированным. Кроме того, если он сортирует, он, вероятно, сортирует их как строки, а «444026-444050 10» предшествует «444026-444050 2» как строки. Возможно, стоит вставить SortObject в ваш конвейер и использовать Split, чтобы получить нужный вам порядковый номер:

Dir *.pdf | Sort-Object -Property {[int]$_.Name.Split()[1].Split(".")[0]} | ForEach-Object  -begin { $count=26 } -process { rename-item $_ -NewName "4440$count.pdf"; $count++ }

Ключевой частью является этот новый этап конвейера, вставленный после Dir и перед ForEach-Object:

Sort-Object -Property {[int]$_.Name.Split()[1].Split(".")[0]}

Это говорит о сортировке вывода Dir в соответствии с тем, что находится между первым пробелом и последующей точкой, сравнивая эти вещи как целые числа (не строки). Это гарантирует, что ваши результаты будут упорядочены и что вы получите их в числовом, а не в лексикографическом порядке.

person Patrick87    schedule 11.02.2020
comment
Хороший момент в том, что лексическая сортировка не равна числовой, но цикл OP, как написано, просто увеличивает и встраивает одно число для каждого входного файла, что превращает 444026-444050 1 в качестве первого файла в 444026, а затем 444026-444050 2 в 444027. , а это значит, что общность префикса 444026 теряется. Я думаю, что сначала нужно уточнить точные требования ОП. - person mklement0; 11.02.2020
comment
Причина, по которой это работает, заключается в том, что sort-object блокируется до тех пор, пока у него не будут все имена файлов. - person js2010; 11.02.2020
comment
@mklement0 Не согласен. dir | rename-item -newname { 'pre' + $_.name } Это создает для меня бесконечный цикл. Использование круглых скобок или сортировка работает вокруг этого. - person js2010; 18.02.2020
comment
Вы правы, @js2010, в отношении Windows PowerShell — я не знал, что поведение предварительной сортировки является эксклюзивным для PowerShell [Core] 6+. - person mklement0; 18.02.2020

Хорошо. Посмотрим, всех ли это порадует. Возможно, вам следует попробовать это с резервной копией файлов.

# make some test files in a new folder
# 1..20 | foreach {
#   if (! (test-path "44026-44050 $_.pdf")) { 
#     echo "44026-44050 $_" > "44026-44050 $_.pdf" }
# }

# rename and pad the first 9 old filenames with a 0 before the last digit for sorting
# is it less than 100 files?
1..9 | foreach {
  ren "44026-44050 $_.pdf" "44026-44050 0$_.pdf" -whatif
}

# make dir complete first with parentheses for powershell 5
# pad $count to 2 digits
# take off the -whatif if it looks ok
(dir *.pdf) | foreach { $count = 1 } {
    $padded = $count | foreach tostring 00
    rename-item $_ -newname 4440$padded.pdf -whatif; $count++ }
person js2010    schedule 11.02.2020
comment
+1 очень интересно. Как вы думаете, если бы я попробовал это, но просто распечатал имена, я мог бы убедиться, что скобки имеют значение? Или я предполагаю, что это что-то вроде условия гонки в том смысле, что иногда он может просто получить список за один раз, а иногда может передавать элементы медленнее? - person Patrick87; 12.02.2020
comment
Вы не можете сказать, не снимая что если. Может попробовать на копии. - person js2010; 12.02.2020
comment
Подводя итог: в Windows PowerShell (v5.1-) вам действительно нужно (...), чтобы переименование работало правильно. Хотя в PowerShell [Core] 6+ это больше не требуется, так как всегда выполняет внутреннюю сортировку, неплохо по-прежнему использовать (...) для концептуальной ясности, особенно с учетом того, что такое поведение можно рассматривать как деталь реализации. . - person mklement0; 18.02.2020
comment
(продолжение) Если бы перечисления выходных данных Get-ChildItem как есть было бы достаточно, ваше решение было бы эффективным; однако в этом случае было необходимо использовать пользовательскую сортировку имен файлов, основанную на интерпретации частей имен файлов как чисел, как показано в принятый ответ, где использование Sort-Object неявно гарантирует, что переименованные файлы не будут мешать перечислению ( потому что сортировка неизменно требует сбора всех входных данных заранее). - person mklement0; 18.02.2020