Переименование файлов с помощью find, sed и xargs
Данное сообщение не претендует на оригинальность, это просто очередной пример того, как можно переименовать много файлов с помощью командной строки в Linux, используя find , sed , xargs и mv .
Общий вид #
- Вывести имена нужных файлов ( ls , echo или find ).
- Произвести замену каждого имени и вывести старое имя и новое имя ( sed ).
- Применить к каждой паре старое имя – новое имя команду mv ( xargs ).
На языке bash эти 3 команды могут выглядеть так:
ls | sed | xargs mv echo | sed | xargs mv find | sed | xargs mv
Мы будем говорить о последнем варианте, поскольку find является очень мощной и гибкой утилитой для поиска файлов.
Пример №1 #
Простейший случай, необходимо произвести такую замену с большим количеством файлов:
01-filename.txt → 01-new.txt 02-filename.txt → 02-new.txt .
Для экспериментов создадим директорию ~/test/ .
Теперь в директории ~/test/ должно появиться 5 пронумерованных файлов. Выведем эти файлы (точка после find означает, что поиск надо проводить в текущей директории; ключ -type f просит выводить только файлы).
find #
./1-filename.txt ./2-filename.txt ./5-filename.txt ./4-filename.txt ./3-filename.txt
Потоковый редактор sed в команде find | sed получает поток названий файлов от find. И с каждым названием файла он может делать какую-то операцию. Нас интересует замена, общий вид которой в sed выглядит так.
sed #
Общий вид команд в редакторе sed:
sed 's/old/new/g' sed 's#old#new#g' sed 's:old:new:g'
Если выполнить данные команды, то sed будет ждать ввода аргументов с клавиатуры. После каждого нажатия Enter sed выведет строку, заменив в ней ‘old’ на ‘new’, если ‘old’ будет присутствовать в введённой строке. Но обычно sed используется либо в связках типа find | sed , либо принимает в качестве аргумента имена файлов, чтобы произвести замены внутри файлов.
Заметьте, что вы сами можете выбирать разделитель — например, / , # или : (хотя можно использовать почти любой символ), комбинировать их нельзя. Буква ‘s’ — заменить (от англ. substitute); буква ‘g’ (от англ. global) в конце стоит для того, чтобы замена происходила во всей строке не только для первого вхождения, а столько раз, сколько там встретится «old». Когда в заменяемых выражениях встречаются слэши ( / или \ ), то каждую из них приходится предварять дополнительным обратным слэшем, тогда код слишком сильно напоминает частокол и удобнее использовать двоеточие или что-то другое в качестве разделителя.
Итак, посмотрим, что мы можем сделать двумя первыми шагами find | sed :
find . -type f | sed 's:filename:new:g'
./1-new.txt ./2-new.txt ./5-new.txt ./4-new.txt ./3-new.txt
Отлично, нужные нам имена выведены. Но в третьем шаге утилите xargs нужны и старое, и новое имя файла, чтобы применить к ним команду mv . Поэтому модифицируем команду sed :
Знак «p;» (p — print), стоящий перед «s», просит sed выдавать не только результат, но и исходный материал. Теперь вывод будет такой:
find . -type f | sed 'p;s:filename:new:g'
./1-filename.txt ./1-new.txt ./2-filename.txt ./2-new.txt ./5-filename.txt ./5-new.txt ./4-filename.txt ./4-new.txt ./3-filename.txt ./3-new.txt
То, что нужно. Переходим к третьему шагу.
xargs #
Программа xargs работает с потоками данных. Утилита принимает один поток и может «распараллелить» его на несколько. Чтобы было лучше понятно, посмотрите простые примеры:
echo "1 2 3 4 5 6 7 8 9" | xargs -n1
echo "1 2 3 4 5 6 7 8 9" | xargs -n2
echo "1 2 3 4 5 6 7 8 9" | xargs -n3
echo "1 2 3 4 5 6 7 8 9" | xargs -n4
Для переименования файлов, очевидно, нам нужен ключик -n2 , тогда xargs разделит поток из старых и новых имён в две колонки.
find . -type f | sed 'p;s:filename:new:' | xargs -n2
./1-filename.txt ./1-new.txt ./2-filename.txt ./2-new.txt ./5-filename.txt ./5-new.txt ./4-filename.txt ./4-new.txt ./3-filename.txt ./3-new.txt
Отлично. Осталось перед каждой парой вставить mv , и переименование произойдёт. Выполняем:
find . -type f | sed 'p;s:filename:new:' | xargs -n2 mv
Вывода никакого не последует, но переименование произошло. Чтобы быть уверенным в результате, можно произвести проверку перед выполнением этой команды. Для этого надо добавить ключ -p к xargs . Тогда утилита будет показывать, что она сделала бы без ключа -p . Можно нажимать Enter и просматривать, что собирается сделать команда. Изменения применены не будут.
find . -type f | sed 'p;s:filename:new:' | xargs -n2 -p mv
Если результаты устраивают, то нужно убрать ключ -p и повторить команду.
Пример №2 #
В директориях dir1/subdir1/ , dir1/subdir2/ ,… dir5/subdir5/ лежат файлы filename.txt. Нужно вытащить их оттуда, но уже с разными именами.
dir1/subdir1/filename.txt → dir1-subdir1-filename.txt dir1/subdir2/filename.txt → dir1-subdir2-filename.txt . dir5/subdir5/filename.txt → dir5-subdir5-filename.txt
При необходимости создадим и очистим нашу экспериментальную директорию ~/test/ и создадим там необходимую структуру файлов:
mkdir -p ~/test/ rm ~/test/* cd ~/test/
mkdir -p dir/subdir touch dir/subdir/filename.txt
Итак, у нас получилось 25 файлов filename.txt в директориях dir1/subdir1/ , dir1/subdir2 ,… dir5/subdir5/ .
find #
Выведем эти файлы. В этом случае -type f тоже сработал бы, но воспользуемся для разнообразия поиском по имени. Также используем звёздочку вместо точки, чтобы избавиться от ведущего ./ в выводе.
dir1/subdir2/filename.txt dir1/subdir4/filename.txt dir1/subdir1/filename.txt dir1/subdir5/filename.txt dir1/subdir3/filename.txt .
sed #
Попросим sed заменить все слэши на дефисы.
find * -name 'filename.txt' | sed 'p;s:/:-:g'
xargs #
find * -name 'filename.txt' | sed 'p;s:/:-:g' | xargs -n2 -p mv
Убедившись, что всё произойдёт правильно, убираем ключ -p и повторяем команду.
Пример №3 #
В директории лежат файлы, пронумерованные от 0 до 1001. Если их выводить командой ls , они будут отсортированы по имени не так, как этого хотелось бы [1] . Добавим необходимое количество нулей в названия файлов.
0-filename.txt → 0000-filename.txt . 50-filename.txt → 0050-filename.txt . 150-filename.txt → 0150-filename.txt . 1001-filename.txt → 1001-filename.txt
При необходимости создаём тестовую директорию и/или чистим её и создаём наши 1001 файл:
mkdir -p ~/test/ rm -r ~/test/* cd ~/test/
Можно действовать так (не лучший вариант).
user test $
user test $
user test $
ls | sed 'p;s:^\(7\)-:000\1-:g' | xargs -n2 mv ls | sed 'p;s:^\(49\)-:00\1-:g' | xargs -n2 mv ls | sed 'p;s:^\(537\)-:0\1-:g' | xargs -n2 mv
Первая команда всем файлам, начинающимся с одной цифры, добавит 3 нуля. Вторая команда всем файлам, начинающимся с двух цифр, добавит 2 нуля. Третья команда всем файлам, начинающимся с трёх цифр, добавит 1 ноль.
Здесь использованы регулярные выражения в sed . Разберём конструкцию
- ^ означает, что нужно искать с начала имени
- конструкция \(. \) позволяет заключённое в неё использовать как \1 в шаблоне замены
- 685 означает три любые цифры подряд.
- — — просто дефис.
- В принципе, с этим можно справиться командой ls -v (natural sorting: 10 будет выведено после 9, а не после единицы), но мы всё-таки для упражнения произведём переименование. ↩︎
© Сергей Лисаков, 2023. Сайт собран Hexo.
Linux переименовать всех файлы
Итак, у нас есть куча файлов, среди которых надо навести порядок. Для этого сделаем групповое переименование.
Утилита rename входит в стандартную поставку Debian, так что начнем с нее.
rename [ -v ] [ -n ] [ -f ] perlexpr [ files ]
-v отобразить имена успешно переименованных файлов.
-n отобразить список файлов, которые будут переименованы, без переименования в итерации.
-f перезаписать уже существующие файлы.
perlexpr — шаблон для переименования.
Для того, чтобы выполнить переименование файлов согласно условию, выполним команду:
Рассмотрим perlexr подробнее:
s=указывает, что требуется замещение.
/.sh/=Строка, которую будем замещать.
/.sh.bak/ = строка, на которую будем замещать
g=global, будем замещать все найденные вхождения.
С помощью rename можно быстро изменить регистр файлов. Например поднимем регистр файлов из примера:
mmv — программа для массового перемещения, переименования, копирования, объединения файлов.
По умолчанию она не включена в состав Debian. Поставим ее:
Наша задача решается одной строкой:
Теперь решим нашу задачу стандартной командой mv. Для этого нам прийдется немного попрограммировать в bash.
for i in *.sh;
do mv $i `basename $i sh`sh.bak;
done
Попробуем усложить задачу. Например у нас есть куча файлов JPG:
1234234.jpg
e456567657.jpg
234df34.jpg
…
Мы хотим привести их к следующему виду:
file1.jpg
file2.jpg
file3.jpg
…
j=0;
for i in *.jpg;
do let j+=1;
mv $i file$j.jpg ;
done
В любимом многими mc, процесс переименования по маске выполняется просто и непринужденно в два действия.
1. Через + выбираем файлы по маске *.sh
2. Нажимаем F6 и в destination указываем *.sh.bak
Все примеры, приведенные выше, так или иначе работают во всех Linux, BSD, Mac OS, если стоят соответствующие утилиты.
Массовое переименование файлов в Linux.
Сегодня я продолжу рассказывать об азах Linux. В качестве примера гибкости и удобства, рассмотрим операцию массового переименования файлов. В общем достаточно тривиальная задача, но в Linux ее можно выполнить не одним и даже не двумя способами. Список примеров не претендует на полноту, но общее представление даст.
Offtop. Переименовать один файл в Linux: mv имя-файла1 имя-файла2
Итак, допустим у нас есть несколько файлов:
myapp.conf myapp.txt myapp.sh whatis.sh
Файлы sh мы хотим переименовать в sh.bak. Рассмотрим варианты:
Утилита rename входит в стандартную поставку Debian, так что начнем с нее.
rename [ -v ] [ -n ] [ -f ] perlexpr [ files ]
-v отобразить имена успешно переименованных файлов.
-n отобразить список файлов, которые будут переименованы, без переименования в итерации.
-f перезаписать уже существующие файлы.
perlexpr — шаблон для переименования.
Для того, чтобы выполнить переименование файлов согласно условию, выполним команду:
Рассмотрим perlexr подробнее:
s=указывает, что требуется замещение.
/.sh/=Строка, которую будем замещать.
/.sh.bak/ = строка, на которую будем замещать
g=global, будем замещать все найденные вхождения.
С помощью rename можно быстро изменить регистр файлов. Например поднимем регистр файлов из примера:
mmv — программа для массового перемещения, переименования, копирования, объединения файлов.
По умолчанию она не включена в состав Debian. Поставим ее:
Наша задача решается одной строкой:
Теперь решим нашу задачу стандартной командой mv. Для этого нам прийдется немного попрограммировать в bash.
Попробуем усложить задачу. Например у нас есть куча файлов JPG:
1234234.jpg e456567657.jpg 234df34.jpg …
Мы хотим привести их к следующему виду:
file1.jpg file2.jpg file3.jpg …
Midnight Commander
В любимом многими mc, процесс переименования по маске выполняется просто и непринужденно в два действия.
Все примеры, приведенные выше, так или иначе работают во всех Linux, BSD, Mac OS, если стоят соответствующие утилиты.
На этом все, спасибо за внимание.