Найти в Дзене
nixCraft

rename — Массовое переименование файлов

Оглавление

Инструмент командной строки rename — это мощное средство для одновременного переименования или даже перемещения нескольких файлов по заданному шаблону.

Однажды, разбираясь с возникшей проблемой не сервере, я скачал папку с логами на свой домашний компьютер. Очень скоро я понял, что читать логи предпочтительнее по дате, для чего мне надо было переименовать все лог-файлы в «правильном» формате. Другой пример. Мой товарищ увлекается фотографированием, и ему каждый раз, после отбора удачных снимков, приходится заниматься переименованием более сотен фотографий.

С изменением имён нескольких файлов можно справиться вручную, но изменение имён более десятка файлов быстро становится не только утомительным, но и чреватым допусками ошибок. В Linux есть несколько инструментов, которые позволяют переименовывать файлы в массовом порядке. В частности, файловый менеджер Thunar имеет очень гибкий инструмент Bulk Rename, с несколькими мощными встроенными критериями сопоставления с образцом, из которых можно выбирать, что делает инструмент достаточным для большинства случаев использования.

Однако, после того, как вы попробуете групповое переименование файлов с помощью командной строки, вы поймёте, что процесс проходит быстрее, чем с помощью графического инструмента. Кроме того, инструмент Bulk Rename в Thunar хоть и мощный, но все же ограничен в своей гибкости. К примеру, Bulk Rename может переименовывать файлы, но не может перемещать файлы из одного каталога или группы каталогов в другой.

В этой статье мы подробно рассмотрим команду rename, мощный инструмент командной строки, написанный на языке Perl, который можно использовать для массового переименования файлов и многого другого.

Начало работы

Установить инструмент командной строки rename на Debian, Ubuntu или их производные дистрибутивы можно командой:

sudo apt install rename

После установки команда rename имеет следующий синтаксис:

rename [options] [expression] [files]

Файлы — это один или несколько файлов для переименования. Как и в других инструментах командной строки, допускаются стандартные подстановочные символы оболочки, такие как *.png или file[0-9].

Выражение состоит из параметров, которые сопоставляют и изменяют части имён файлов. Результаты применения выражения к каждому имени файла используются для присвоения файлу нового имени. Обычно указывается только одна команда — команда s/// для поиска и изменения имён файлов. Команда y/// используется реже, в основном для замены или транслитерации отдельных букв.

Но на самом деле выражением может быть практически любой допустимый код Perl, оперирующий со строками. Если вы интересуетесь выражениями Perl, обратитесь к официальной документации по Perl. Однако маловероятно, что для изменения имён файлов вам понадобится что-то большее, чем команды s/// и y///.

Кроме того, rename принимает одну или несколько опций, наиболее полезные из них приведены в таблице ниже.

Таблица 1. Параметры переименования

-2

Простой пример

Для первого примера я сохранил несколько HTML-файлов со статьями из Википедии. Браузер назвал каждую веб-страницу по её заголовку, которые заканчивались дефисом и словом «Википедия», что является лишним и неоправданно удлиняет имя каждого файла.

ls -N |more
IEEE 802.11n — Википедия.html
Linux — Википедия.html
Квалификаторы типа — Википедия.html
Квантовая вероятность — Википедия.html
Оксид железа(III) — Википедия.html

Чтобы удалить в конце имени каждого файла пробелы, дефис и слово «Википедия», воспользуемся следующей командой:

rename -v 's/ — Википедия\.html$/.html/' *.html

-3

Команда s/// ищет часть имени файла, соответствующую шаблону, который заключён между первыми двумя косыми чертами (фигурная скобка 1 на скриншоте выше). Далее заменяет найденный текст на другой, заключенный между второй и третьей косыми чертами (фигурная скобка 2).
Ниже показан результат выполнения этой команды.

ls -N |more
IEEE 802.11n.html
Linux.html
Квалификаторы типа.html
Квантовая вероятность.html
Оксид железа(III).html

Обратите внимание на символ обратной косой черты «\», предшествующий символу точки «.» в поисковом выражении, который мы использовали выше. Из-за того, что символ точки имеет особое значение в регулярных выражениях, имеет смысл использовать перед ним обратную косую черту (так называемый escape). Если этого не сделать, то символ точки будет соответствовать не только одиночному символу точки в имени файла, но и любому другому символу. В нашем примере, без экранирования точки, rename искал бы соответствие на такие имена как — « — Википедияahtml», « — Википедияzhtml», « — Википедия!html» и так далее.

Конкретно в нашем случае, имена файлов, которые я хочу переименовать, не содержит ничего, кроме «* — Википедия.html», поэтому экранирование символа точки в данном случае излишне. Однако, формулируя поисковые запросы, следует быть как можно более конкретным.

Символ точки — один из нескольких метасимволов, которые имеют особое значение в регулярных выражениях. Знак доллара «$» в конце поискового выражения указывает rename на соответствие части имени файла только в том случае, если совпадение происходит в конце имени файла.

Таблица 2. Метасимволы регулярных выражений

-4

Например, файл «Квантовая вероятность — Википедия.html» будет соответствовать регулярному выражению, которое я использовал ранее. А вот файл «ААА — Википедия.html.gz», который оканчивается на «.gz» не будет соответствовать. Как и в случае с символом точки, для соответствия буквальному символу знака доллара в имени файла перед знаком доллара должен был бы стоять обратный слеш.

Вы также можете указать один или несколько символов, следующих за завершающей косой чертой в команде s///. Эти символы дополнительно изменяют поведение операции поиска и замены, например, отключают сопоставление с учетом регистра. Ниже рассмотрим подробности о параметрах, поддерживаемых командой s///.

Параметры s///

Добавив один или несколько дополнительных символов в конец команды s///, можно изменить поведение операции поиска и замены различными способами. Каждая опция — это один символ. Несколько опций могут быть указаны, если сразу после одного символа опции следует другой. Примеры:

  • s/dog/cat/g,
  • s/.html$/.HTM/i,
  • s/recieve/receive/gi.

Хотя и поддерживается более десятка вариантов опций, но только два из них действительно полезны для большинства пользователей при переименовании файлов. Первая — это «g», указывает rename заменить все вхождения строки поиска строкой замены, а не только первое вхождение. По умолчанию заменяется только первое вхождение поискового термина. В большинстве случаев этого достаточно, но не в том случае, если вы хотите заменить все вхождения, например, слова «аффект» на «эффект» в имени файла «аффект_аффективности_приводит_к_аффекту.txt».

Другая потенциально полезная опция, «i», обеспечивает поиск без учета регистра. Другими словами, rename будет неважно, в верхнем или нижнем регистре находится символ в строке поиска. Любой из этих символов будет соответствовать любому из символов в имени файла. По умолчанию, если символ в строке поиска является строчным, соответствующий символ в имени файла также должен быть строчным, чтобы строка поиска совпала. Например, без параметра «i» поисковый запрос «.html» будет соответствовать файлу «test1.html», но не «test2.HTML» или «test3.Html». Напротив, с параметром «i» то же самое поисковое выражение будет соответствовать всем трём файлам. Даже если все или часть поискового выражения будут написаны с заглавной буквы.

Использование обратных ссылок

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

Но иногда возникает необходимость переименовать файлы более сложными способами. В следующем примере, у меня есть несколько лог-файлов с датами и временем в именах. Имя каждого файла содержит год, месяц, день, час, минуту и секунду, в которые был создан лог-файл, в соответствии с конвенцией ISO 8601, международным форматом дат и времени.

ls -N |more
daemon_20200309_071842
messages_20211213_134327
messages_20230402_093200
syslog_20191013_233611
syslog_20220726_185603

Но предположим, что я хочу, чтобы даты и время были заданы в более удобном для меня формате. Так, в моём случае, я хочу, чтобы в именах файлов между компонентами даты (день.месяц.год) вставлялись точки, а между компонентами времени (часы:минуты:секунды) — двоеточия. Ниже показано, как должны выглядеть имена файлов после их переименования.

ls -N |more
daemon_09.03.2020_07:18:42
messages_13.12.2021_13:43:27
messages_02.04.2023_09:32:00
syslog_13.10.2019_23:36:11
syslog_26.07.2022_18:56:03

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

Регулярные выражения позволяют ссылаться на части строки поиска в строке замены с помощью обратных ссылок. Чтобы использовать обратные ссылки, часть строки поиска, на которую нужно сослаться, нужно заключить в круглые скобки. После чего эти части, заключённые в круглые скобки, могут быть отнесены к строке замены, путём вставки в строку замены символа знака доллара «$», за которым следует номер индекса.

Следующая команда rename использует обратные ссылки для выполнения моей первой задачи по изменению порядка следования компонентов дат, а также вставляет точки между компонентами:

rename -v 's/([0-9]{4})([0-9]{2})([0-9]{2})/$3\.$2\.$1/' *

На рисунке ниже показано, на какие части поискового выражения ссылается каждая обратная ссылка. Стрелки на рисунке указывают на области поискового выражения, на которые ссылаются скобки.

-5

Комбинирование нескольких операций

В предыдущем примере были переформатированы только даты. Но мне всё ещё нужно вставить двоеточия между каждым компонентом времени. И снова я могу использовать обратные ссылки, как показано ниже:

rename -v 's/([0-9]{2})([0-9]{2})([0-9]{2})$/$1:$2:$3/' *

Такой вариант тоже имеет право на существование. Но я хочу использовать одну единственную команду rename для изменения даты и времени вместо того, чтобы последовательно выполнять две отдельные команды. Конечно же, я мог бы объединить два поисковых выражения в одно очень длинное поисковое выражение, которое получится громоздким и трудночитаемым:

rename 's/([0-9]{4})([0-9]{2})([0-9]{2})_([0-9]{2})([0-9]{2})([0-9]{2})$/$3\.$2\.$1_$4:$5:$6/' *

К счастью, в rename можно выполнить обе задачи одной командой, но при этом сохранить их логическое разделение. Если каждое выражение разделено точкой с запятой, rename может выполнить два или более выражений в одной команде:

rename -v 's/([0-9]{4})([0-9]{2})([0-9]{2})/$3.$2.$1/;
s/([0-9]{2})([0-9]{2})([0-9]{2})$/$1:$2:$3/' *

Обратите внимание на новую строку после точки с запятой. Хотя это и не обязательно, но улучшает читаемость поискового выражения. Команда rename интерпретирует его как безобидный символ пробела.

Транслитерация символов

Команда y/// транслитерирует текст. Она ищет каждый символ, указанный в первом параметре команды, и заменяет любой его экземпляр на соответствующий символ во втором параметре. Например, чтобы заменить в именах файлов все AZ на ZA, или ZA на AZ , используйте команду:

rename 'y/AZ/ZA/' *

После выполнения этой команды файл «AZGREB.TXT» станет «ZAGREB.TXT».

Хотя команда y/// чувствительна к регистру, как и s///, у команды y/// нет переключателя опций для включения чувствительности к регистру. Таким образом, приведенная выше команда y/// заменит ZAGREB.TXT, но не zagreb.txt. Более того, она заменит Zagreb.txt на Aagreb.txt, но не на Azgreb.txt, как вы могли бы ожидать. Чтобы сделать это, вам нужно изменить команду на:

rename 'y/AZaz/ZAza/' *

Одно из распространенных применений команды y/// — преобразование прописных имен файлов в строчные или наоборот. Это может оказаться полезным для старых файлов MS-DOS или ранних версий Windows, которые сохраняли файлы в верхнем регистре. Можно реализовать такую транслитерацию, явно указав в команде весь алфавит, но это громоздко, поскольку в этом случае придется набрать не менее 52 букв: 26 прописных букв в выражении поиска и 26 строчных букв в выражении замены. Вместо этого можно указать диапазоны символов в поисковом выражении, как в y/[A-Z]/[a-z]/, для замены прописных символов на их строчные эквиваленты.

Как и команда s///, команда y/// принимает один или несколько параметров, следующих за последней косой чертой команды. Ни одна из этих опций, скорее всего, не будет полезна для общих целей, но c и d могут иметь некоторые нишевые применения, и об этом ниже.

Опции y///

Как и команда s///, команда y/// может принимать несколько опций, и каждая опция по-своему изменяет поведение команды y///. Среди множества опций y/// можно выделить две, «c» и «d», как наиболее полезные.

Обе эти опции используются в связи с присущим y/// поведением, известным как сминание: если количество символов в списке замены меньше количества символов в списке поиска, последний символ в списке замены дублируется до тех пор, пока длина списков поиска и замены не сравняется. Например,

y/[A-Z]/x/

эквивалентно:

y/[A-Z]/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/

Оба выражения заменят любую прописную букву на строчную x. Однако первое выражение гораздо компактнее и легче читается.

Опция «c», предписывает y/// дополнить список символов в списке поиска и заменить любой символ, отсутствующий в списке. В сочетании со сглаживанием это можно использовать для замены запрещенных символов, отсутствующих в списке поиска, на один конкретный символ-заместитель. Напомню, что файловые системы *nix/Linux могут обрабатывать большинство непечатаемых символов в именах файлов. Например, если у вас есть файлы с непечатаемыми символами в именах, вы можете быстро очистить такие имена файлов, заменив все неалфавитные, нечисловые и прочие символы в именах файлов на символы точки (.), как в примере:

y/[A-Z][a-z][0-9]_-/./c

Другая опция «d», отключает сминание и удаляет любой символ в конце списка замены, не имеющий соответствующего символа в списке поиска. Таким образом,

y/.[A-Z]/.[a-d]/d

преобразует имя файла «DOC_1993.BAK» в «dc_.ba». Хотя этот пример надуман, он характерен для переключателя опций с ограниченной практической пользой.

Перемещение файлов между каталогами

Ещё одно возможное использование переименования — размещение каждой категории лог-файлов в своем каталоге. Как вы помните, у меня есть пять лог-файлов с именами daemon, syslog и messages. На практике, таких файлов в каталоге может оказаться сотни или даже тысячи. Следовательно, я хочу переместить каждый тип лог-файла в свой собственный каталог, например файл «syslog_13-10-2019_23:36:11» должен быть перемещен в каталог «syslog». В идеале я бы хотел, чтобы начальная часть имени лог-файла была удалена, поскольку имя содержащегося каталога должно чётко указывать на тип лог-файла. Ниже показано желаемое результирующее дерево каталогов.

ls -FNR
.:
daemon/ messages/ syslog/
./daemon:
09-03-2020_07:18:42
./messages:
02-04-2023_09:32:00 13-12-2021_13:43:27
./syslog:
13-10-2019_23:36:11 26-07-2022_18:56:03

И опять-таки, rename может перемещать файлы так же легко, как и переименовывать их. Более того, он может сделать и то, и другое в один приём. Очевидно, что в данном случае я хочу сделать и то, и другое одновременно, потому что я хочу переместить файл, а затем удалить первую часть его имени.

К сожалению, чтобы переместить файл в другой каталог, rename требует, чтобы каталог назначения уже существовал. Перед запуском rename вам придется предварительно создать все необходимые каталоги. Я использовал следующую однострочную команду оболочки для создания каталогов перед запуском rename:

find . -maxdepth 1 -type f -printf '%f\0' | grep -Eoz '^[^_]+' |xargs -0 mkdir

В этой команде перечислены все файлы, находящиеся непосредственно в текущем каталоге, а затем берется часть имени файла до первого подчеркивания (например, «messages») и создается новый каталог в текущем каталоге с именем, соответствующим первой части имени файла.

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

rename 's/^([^_]+)_/$1\//' *

Здесь следует отметить несколько моментов. Во-первых, я указал rename искать в самом начале имени файла строку любой длины, которая не содержит подчеркивания (^([^_]+) в поисковом выражении. Это позволяет использовать тот факт, что тип файла журнала отделяется от даты подчеркиванием. Затем я использую обратную ссылку, за которой следует косая черта в выражении замены, чтобы указать rename переместить файл в каталог, названный так, как было сопоставлено вышеупомянутое выражение в круглых скобках.

Обратите внимание, как я экранировал символ косой черты «\/», чтобы гарантировать, что rename не примет косую черту за конец выражения замены. Помните, что выражения поиска и замены, а также любые опции команды s/// разделяются символами косой черты. На самом деле я мог бы использовать практически любой символ для разделения частей команды s///, хотя использование косой черты является общепринятым. Я мог бы использовать знак «@» в приведенной выше команде rename или в любой из предыдущих команд s///. Следующая команда сработала бы так же хорошо:

rename 's@^([^_]+)_@$1/@' *

Благодаря использованию символа, отличного от косой черты, для разделения частей команды s///, мне больше не нужно экранировать косую черту в выражении замены, обозначающем часть пути к каталогу. На мой взгляд, это делает команду более удобной для чтения. Просто убедитесь, что выбранный вами символ не встречается ни в выражении поиска, ни в выражении замены, или же экранирован там, где он встречается.

Заключение

После того как вы поймете синтаксис команды rename, она станет эффективной и очень мощной утилитой для выполнения практически любых задач по массовому переименованию — от преобразования имен файлов в регистр заголовков до перемещения файлов в разные каталоги и замены номеров месяцев на их названия (например, 2015-02-17 на 2015-Feb-17). Все эти и другие задачи можно выполнить с помощью rename. Более того, несколько заданий можно объединить в одну команду для еще большей мощности и гибкости.

В этой статье мы рассмотрели ряд примеров, демонстрирующих основные возможности rename, но я лишь прошёлся по поверхности того, что можно сделать с помощью этой команды. Надеюсь, вы вдохновитесь на создание собственных команд переименования.