пред. след. стартстоп
0 0
Добавлено в корзину

Rename files

 

 

поиск
RDP win
sed
Ubuntu
    rename-files
кодировки
виртуалки
полезности 
 

 


Переименование файлов с помощью find, sed и xargs

Данное сообщение не претендует на оригинальность, это просто очередной пример того, как можно переименовать много файлов с помощью командной строки в Linux, используя find, sed, xargs и mv.

Общий вид

Идея такая:

  1. Вывести имена нужных файлов (ls, echo или find).
  2. Произвести замену каждого имени и вывести старое имя и новое имя (sed).
  3. Применить к каждой паре старое имя – новое имя команду mv (xargs).

На языке bash эти 3 команды могут выглядеть так:

user ~ $
user ~ $
user ~ $
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/.

user ~ $
user ~ $
mkdir ~/test/
cd ~/test/
user test $
touch {1..5}-filename.txt

Теперь в директории ~/test/ должно появиться 5 пронумерованных файлов. Выведем эти файлы (точка после find означает, что поиск надо проводить в текущей директории; ключ -type f просит выводить только файлы).

find

user test $
find . -type f
./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:

user test $
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:

sed 'p;s:old:new:g'

Знак «p;» (p — print), стоящий перед «s», просит sed выдавать не только результат, но и исходный материал. Теперь вывод будет такой:

user test $
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 работает с потоками данных. Утилита принимает один поток и может «распараллелить» его на несколько. Чтобы было лучше понятно, посмотрите простые примеры:

user ~ $
echo "1 2 3 4 5 6 7 8 9"
1 2 3 4 5 6 7 8 9
user ~ $
echo "1 2 3 4 5 6 7 8 9" | xargs -n1
1
2
3
4
5
6
7
8
9
user ~ $
echo "1 2 3 4 5 6 7 8 9" | xargs -n2
1 2
3 4
5 6
7 8
9 
user ~ $
echo "1 2 3 4 5 6 7 8 9" | xargs -n3
1 2 3
4 5 6
7 8 9
user ~ $
echo "1 2 3 4 5 6 7 8 9" | xargs -n4
1 2 3 4
5 6 7 8
9 

Для переименования файлов, очевидно, нам нужен ключик -n2, тогда xargs разделит поток из старых и новых имён в две колонки.

user test $
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, и переименование произойдёт. Выполняем:

user test $
find . -type f | sed 'p;s:filename:new:' | xargs -n2 mv

Вывода никакого не последует, но переименование произошло. Чтобы быть уверенным в результате, можно произвести проверку перед выполнением этой команды. Для этого надо добавить ключ -p к xargs. Тогда утилита будет показывать, что она сделала бы без ключа -p. Можно нажимать Enter и просматривать, что собирается сделать команда. Изменения применены не будут.

user test $
find . -type f | sed 'p;s:filename:new:' | xargs -n2 -p mv
mv ./1-filename.txt ./1-new.txt ?...

Если результаты устраивают, то нужно убрать ключ -p и повторить команду.

добавить 180- в начале имени файла в текущей папке:
find * -maxdepth 0 -type f | sed 'p;s:^:181-:g' |xargs -n2 mv

только добавить расширение .txt к файлам в текущей папке:
find * -maxdepth 0 -type f | sed 'p;s:$:\.txt:g' | xargs -n2 mv

Пример №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/ и создадим там необходимую структуру файлов:

user ~ $
user ~ $
user ~ $
mkdir -p ~/test/
rm ~/test/*
cd ~/test/
user test $
user test $
mkdir -p dir{1..5}/subdir{1..5} 
touch dir{1..5}/subdir{1..5}/filename.txt

Итак, у нас получилось 25 файлов filename.txt в директориях dir1/subdir1/, dir1/subdir2,… dir5/subdir5/.

find

Выведем эти файлы. В этом случае -type f тоже сработал бы, но воспользуемся для разнообразия поиском по имени. Также используем звёздочку вместо точки, чтобы избавиться от ведущего ./ в выводе.

user test $
find * -name 'filename.txt'
dir1/subdir2/filename.txt
dir1/subdir4/filename.txt
dir1/subdir1/filename.txt
dir1/subdir5/filename.txt
dir1/subdir3/filename.txt
...

sed

Попросим sed заменить все слэши на дефисы.

user test $
find * -name 'filename.txt' | sed 'p;s:/:-:g'

xargs

Завершаем переименование:

user test $
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 файл:

user ~ $
user ~ $
user ~ $
mkdir -p ~/test/
rm -r ~/test/*
cd ~/test/
user test $
touch {0..1001}-filename.txt

Можно действовать так (не лучший вариант).

user test $
user test $
user test $
ls | sed 'p;s:^\([0-9]\)-:000\1-:g' | xargs -n2 mv
ls | sed 'p;s:^\([0-9][0-9]\)-:00\1-:g' | xargs -n2 mv
ls | sed 'p;s:^\([0-9][0-9][0-9]\)-:0\1-:g' | xargs -n2 mv

Первая команда всем файлам, начинающимся с одной цифры, добавит 3 нуля. Вторая команда всем файлам, начинающимся с двух цифр, добавит 2 нуля. Третья команда всем файлам, начинающимся с трёх цифр, добавит 1 ноль.

Здесь использованы регулярные выражения в sed. Разберём конструкцию

^\([0-9][0-9][0-9]\)-
  • ^ означает, что нужно искать с начала имени
  • конструкция \(...\) позволяет заключённое в неё использовать как \1 в шаблоне замены
  • [0-9][0-9][0-9] означает три любые цифры подряд.
  • - — просто дефис.

  1. В принципе, с этим можно справиться командой ls -v (natural sorting: 10 будет выведено после 9, а не после единицы), но мы всё-таки для упражнения произведём переименование.

 

 Как заменить пробелы в именах файлов символами подчеркивания в оболочке Linux

 

При работе с Linux вы можете столкнуться с некоторыми утилитами и приложениями, которые работают только с именами файлов, которые не содержат пробелов. Мы не всегда сохраняем файлы в этом формате «без пробелов» и, возможно, придется искать обходной путь, который заменяет пробелы в именах файлов символами подчеркивания «_». Таким образом, ваши имена файлов не будут содержать пробелов, и вы сможете легко работать с ними во всех приложениях. В этой статье мы объясним два способа преобразования всех пробелов в именах файлов в подчеркивания, очень просто через командную строку. Мы запустили команды и процедуры, упомянутые в этой статье, в системе Ubuntu 18.04 LTS. Папка «Мои загрузки», которую я буду использовать в качестве примера для этой статьи, содержит пробелы во всех именах файлов.

$ ls Downloads
 

Метод 1: С помощью одной команды mv

В этом методе мы будем использовать команду Ubuntu mv в цикле for для переименования всех файлов / папок в данном каталоге, чтобы все пробелы в их именах заменялись символами подчеркивания. Откройте командную строку 
Вот синтаксис команды, которую вы будете использовать:

$ for file in *; do mv "$file" `echo $file | tr ' ' '_'` ; done

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

Метод 2: Использование сценария для переименования файлов

В этом методе мы будем использовать сценарий bash, который использует команду mv для переименования имен файлов и папок таким образом, что все пробелы заменяются подчеркиваниями. Откройте приложение Terminal и перейдите в папку bin следующим образом:

$ cd ~bin

Теперь откройте новый файл сценария в одном из ваших любимых текстовых редакторов. Мы будем использовать редактор nano, чтобы открыть пустой файл сценария с именем replace_spaces.sh

$ sudo nano replace_spaces.sh

В этот пустой файл добавьте следующий сценарий:

#!/bin/bash
     for f in *
          do
               new="${f// /_}"
               if [ "$new" != "$f" ]
                    then
                         if [ -e "$new" ]
                              then
                                   echo not renaming \""$f"\" because \""$new"\" already exists
                             else
                                  echo moving "$f" to "$new"
                            mv "$f" "$new"
                       fi
              fi
done

Совет: Вместо этого набрав весь скрипт в ваш bash-файл, вы можете скопировать его отсюда и вставить в терминал, используя Ctrl + Shift + V, или используя опцию Paste из контекстного меню. Необходимо сделать  сделать этот файл исполняемым сценарием, запустите следующую команду в своем терминале:
$ sudo chmod +x replace_spaces.sh
Теперь вы готовы использовать сценарий в любой из ваших папок. Когда я запускаю сценарий в В моей папке «Загрузки» я вижу, что все пробелы в именах моих файлов преобразованы в подчеркивания следующим образом: Таким образом, это были два способа, которыми вы можете переименовывать файлы, чтобы все пробелы в их имена преобразуются в подчеркивания. Теперь любое приложение, которое вы используете, не сможет распознать имена файлов, содержащие пробелы.

отсюда