Как массово переименовать файлы по маске в PowerShell

Как массово переименовать файлы по маске в PowerShell

Невинный пост в группе ВК о сочетании клавиш проводника Ctrl + Shift + N внезапно зацепил приверженцев альтернативных файловых менеджеров. По ходу дела всплыла тема массового переименования файлов.

Евгений Генеральчик подметил, что в отличие от Total Commander, проводнику не по зубам переименование 20 тысяч файлов, например, добавление к имени файла текущей даты. Действительно, в классической серии пенальти я сам признал незаменимым сочетание Ctrl + M в TC, сфокусировавшись на функции поиска/замены.

Однако, отвечая Евгению в ВК, я заметил, что его задачу переименования решу в PowerShell и даже ванлайнером . Написал и подумал – надо все-таки решить, а то вдруг попросят пруфов :)

[+] Сегодня в программе

Переименование файлов методом «поиск / замена»

Через несколько минут у меня получился такой вариант:

На самом деле в команде одна строка, а на две я ее разбил, чтобы она лучше читалась. Давайте разберем составляющие команды.

Выборка файлов

Для получения списка файлов я использую командлет Get-ChildItem. Он же gci, он же ls, он же Элла Кацнельбоген dir, а эта команда прекрасно знакома всем, кто написал хоть один батник .

  • -Path $env:userprofile\Downloads – файлы ищутся по заданному пути, т.е. в папке Downloads в профиле пользователя
  • -Filter "*.zip" – фильтруются только файлы с расширением ZIP. Впрочем, в выборку попадут также и файлы, содержащие в имени ".zip", но этим я пренебрегу. В принципе, можно не указывать параметр, а просто написать .zip.
  • -Recurse – поиск ведется рекурсивно, т.е. во всех вложенных папках. Кстати, в PowerShell 5.0, т.е. в Windows 10, у gci появился новый параметр -Depth, задающий глубину рекурсии. Например, 0 – только текущая папка, 2 – на два уровня вглубь.

Выбранные файлы по конвейеру передаются дальше для переименования.

Переименование файлов

Командлет Rename-Item тоже обладает хорошо известным псевдонимом ren. С помощью параметра -NewName задается новое имя, а в фигурных скобках стоит выражение, задающее условия переименования

  • $_.Name – для каждого переданного по конвейеру файла $_ изменяется полное имя .Name
  • -Replace "\.zip$", "-дата.zip" – я слегка упростил конструкцию, написав дату словом, чтобы был понятен смысл аргументов оператора -Replace: ‘что ищем’, ‘на что меняем’. Здесь тонкость в том, что у -Replace первый аргумент — регулярное выражение, а не просто поиск текста. В регулярных выражениях точка означает любой символ, поэтому использование ".zip" чревато нежелательным переименованием, например, файла winzip-setup.exe.
  • "-$(Get-Date -Format ).zip" – подставляем мы все-таки текущую дату в формате 2015-09-04. Формат дат я уже разбирал, а здесь хочу обратить ваше внимание на другой фокус. Выражение (в данном случае – командлет) не получится вставить просто так в аргумент оператора, но его можно поместить между круглыми скобками такой конструкции $().
  • -WhatIf – этот стандартный параметр в переводе означает «что будет, если». Когда он добавлен в команду, ее реального выполнения не происходит, а в консоль выводится результат того, что могло бы произойти без этого параметра. Другими словами, вы можете проверить команду у себя, не опасаясь, что все архивы переименуются :)

Переименование файлов путем добавления счетчика

По ходу обсуждения в ВК выяснилось, что пример с датой надуманный, а более реальной выглядит последовательная нумерация файлов. Действительно, в TC я часто использовал очень удобный счетчик [C] для переименования графических файлов.

В PowerShell его тоже можно реализовать. Допустим, надо добавить счетчик из трех цифр в конце имени всех файлов JPG в текущей папке. Команда может быть такой:

С выборкой все понятно, поэтому давайте разберем переименование.

  • % — псевдоним командлета Foreach-Object, который перебирает по одному все переданные по конвейеру объекты. За ним следуют два блока скриптов в фигурных скобках < >, о которых чуть ниже.
  • – первый блок, в котором переменная i получает значение 1. Это нужно для счетчика, который после переименования каждого объекта будет увеличиваться на единицу с помощью $i++.
  • ren $_ — начало второго блока для переименования каждого полученного по конвейеру объекта.
  • "$($_.Basename)-.png" – новое имя файла. Конструкцию $() я разбирал выше, но здесь я использую свойство Basename, т.е. имя файла без расширения (Name – имя файла с расширением).– счетчик, причем в данном случае он трехзначный, что определяется конструкцией из трех символов 00# после двоеточия. Эквивалентом будет , где число после D задает количество символов счетчика.
Примечание о блоках скриптов

Существует три типа блоков:

  • Begin (начало) — выполняется один раз в самом начале, до перебора элементов
  • Process (обработка) — выполняется для каждого элемента
  • End (конец) — выполняется в самом конце перебора

Командлет Foreach-Object обрабатывает блоки особым образом. Если ему указать только один блок, он воспринимает его как Process. Если два, то первый будет Begin, а второй — Process (наш случай). Если все три, то поведение стандартное: Begin → Process → End.

Дискуссия

Я не ставил перед собой задачу описать на языке PowerShell эквиваленты всех функций массового переименования Total Commander. Думаю, что это вполне возможно, а степень успеха зависит лишь от вашего уровня владения PowerShell, .NET и гуглояндексом. Вопрос лишь в том, насколько это целесообразно.

Графический интерфейс TC понятнее, нагляднее и не требует специальной подготовки. Однако бывают ситуации, когда вы не сможете воспользоваться любимым инструментом. Например, его нет в системе, а установить нельзя, поскольку ПК изолирован от внешней среды или это запрещено политикой организации. Если вы не ленитесь расширять свой кругозор и не упускаете случая поковырять PowerShell, вы с честью выйдете из такой ситуации.

Кстати, в ближайших записях я познакомлю вас с некоторыми новыми возможностями платформы PowerShell 5.0, включенной в Windows 10.

Расскажите в комментариях, какую задачу вы в последний раз решали:

  • с помощью PowerShell или другого скриптового языка
  • средства для массового переименования в любимом файловом менеджере

Я благодарю Василия Гусева за ценные дополнения, которые я добавил в статью после публикации.

Об авторе

Вадим - владелец этого блога, и почти все записи здесь вышли из-под его пера. Подробности о блоге и авторе здесь. Поддержать автора вы можете тут.

Вас также может заинтересовать:

Я в Telegram

Подпишитесь на канал и читайте интересные записи чаще! Есть вопросы? Задайте их в чате.

комментариев 50

знак «`» не обязательно ставить, т.к. PowerShell после | будет искать продолжение строки.

Паша, спасибо, я учту.

В последний раз решал задачу посылки любого sms сообщения через usb gsm «свисток». Причем скрипт работает как в оконном режиме(PowerGUI помог), так и в консольном.

Завидую (по хорошему) Вашей памяти, Вадим. Мне вот никак не удается весь этот «язык пляшущих человечков» запоминить. Это я относительно Вашей фразы про то, как PoSH может помочь в случае если Total поставить нельзя. Мне в этом случае поможет либо многочасовое чтение манов либо (если вдруг на таком ПК окажется инет) гугление.

Алекс, вы же ИТ-специалист? Тогда базовым английским владеете, а суть командлетов понятна из названия. Я их намного лучше понимаю, чем синтаксис команды FOR из CMD, который я так и не осилил, и без знания которого такие задачи не решаются.

Да, в этом случае Get-ChildItem не слишком очевиден, но это потому, что он не только к папкам применим, а еще и к реестру (gci hkcu:), хранилищу сертификатов и т.п. Но я в записи подчеркиваю псевдонимы dir, ren — не сложнее, чем в CMD :)

А нет ли способов уменьшить нагрузку на память, для уже решенных задач? Простых и быстрых. Записать эту команду в функцию и вызывать BulkRename *.jpg . или BulkRename *.jpg ., где «2» — количество знаков в нумерации, а «1» начальное значение счетчика.

Можно и функцию написать, было бы желание (у меня его нет :)

Кто-нибудь объяснит, зачем переименовывать 20000 файлов? Такое бывает вообще? Приведите примеры. А сколько файлов можно переименовать в проводнике? Хотя опять напрашивается вопрос — Зачем. Разве в Проводнике недостаточно инструментов для управления файлами?

Ок, пусть 20 файлов — как решать будете обе задачи в проводнике?

Да в легкую. Даже не заморачиваясь ни на чем создал 40 файлов https://cloud.mail.ru/public/3Zbq/uzYUwJjnz И переименовал и задал теги. А Тотал командер может работать с тегами в этом ракурсе?

Мда… Ладно, проехали.

Оно то переименовало, только что вы с такими похабными именами делать будете?

Живой пример, надо загрузить галерею фоток к статье на новостной сайт.

Заливать как DSCN0005.JPG и т.п. не вариант, так как редактор потом никогда не разберется какие фотки откуда. Принято правило именовать фотки как имя_статьи-00N.JPG, все латиницей и без пробелов. Как это сделать проводником?

Скриптом без проблем, хотя мы используем Bulk Rename.

А вот еще пример https://cloud.mail.ru/public/4bbb/vdWnPN2yr Вообще не понимаю, в чем здесь увидели проблему. В проводнике все удобно работает. Никакие тоталы и фары не нужны. Никакие скрипты не нужны. Никакие языки не нужны. Или задача состоит в том, кто изощренней будет изголяться? Пусть те, кто тыркается с тоталом, лучше поучится работать с Проводником. Либо у них действительно, прямая дорога назад в дос.

Ваши примеры того, что вы не читали статью, больше не нужны, спасибо.

Ладно, статью вы не поняли, давайте тогда про другое: а если надо будет в какой-то тег каждого файла записать его номер, который присутствует в имени этого же файла, вы это сможете сделать проводником для 640 файлов?

Последнее из того, что могу вспомнить — сортировка файлов, извлечённых по сигнатурам из образа диска с убитой файловой системой. Была написана программа (на C++), которая посекторно сканирует файл образа диска (дамп, полученный программой dd, которая есть и для Windows) и при обнаружении известной сигнатуры начинает выписывать новый файл. Имена полученных файлов в большинстве случаев имеют вид: «XXXX YYYYYYY.rar», где XXXX — порядковый номер файла, YYYYYY — номер сектора, с которого файл начинается на диске.

Для сортировки файлов были написаны адские батники, которые могли: — Устранять копии. В первой версии файлы сравнивались каждый с каждым при помощи утилиты fc /b (fc умеет устанавливать errorlevel), но этот алгоритм имеет квадратичную сложность (время O(N²)), поэтому для больших наборов он уже не подходил. Стал перемещать файлы в каталог с именем из хеш-кода (вычисленного утилитой fciv.exe). Затем другой скрипт обходил подпапки и сохранял только самый первый файл из каждой из них (остальные удалял). — Добавлять примерную дату создания к имени каждого архива. Архив извлекался во временную папку с восстановлением точного времени всех временных штампов (winrar x -ts arc.rar temp\), циклом for /r перебирались все файлы и выбиралась самая поздняя дата модификации. — Сортировать архивы по содержимому. Утилитой rar.exe извлекался листинг каждого архива, команда find определяла наличие ключевого слова (она тоже устанавливает errorlevel в зависимости от результата), при успешном обнаружении архив перемещался в соответствующую подпапку.

О существовании средства массового переименования файлов в Far Manager’е я ничего не знаю, возможно есть соответствующие плагины, искать не пробовал.

В некоторых простых случаях для массового переименования/копирования файлов в Far я сначала создавал список файлов в новом текстовом файле: dir /b *.abc > rename.bat Затем правил rename.bat встроенным редактором, как правило, записывая макрокоманду. Потом нажимал горячую клавишу макрокоманды (как правило, Ctrl+Alt+↓) для каждой строчки в файле. Либо просто записывал макрокоманду, которая в командной строке Far’а формирует команду переименования файла под курсором, тут же её выполняет (нажимает Enter) и переходит к следующему файлу (нажимает ↓). И опять давил на горячую клавишу десяток-другой раз.

Возвращаясь к cmd.exe. Мне кажется, я слишком хорошо знаю обычную командную строку, чтобы заставить себя начать изучать PowerShell. Нумерация файлов в текущем каталоге:

Добавление текущей даты будет отличаться использованием %DATE% вместо %SUF:

-3% в процедуре RENAME. Недостаток по сравнению с однострочником PowerShell — нужно создавать файл. И я тоже не помню наизусть все ключи команд set и for, но их всегда можно посмотреть командами set /? и for /?.