AWK, SED, REGEX для переименования файлов

Я только учусь использовать REGEX, AWK и SED. В настоящее время у меня есть группа файлов, которые я хотел бы переименовать — все они находятся в одном каталоге.

Шаблон именования согласован, но я хотел бы изменить имена файлов, вот формат:

01._HORRIBLE_HISTORIES_S2.mp4
02._HORRIBLE_HISTORIES_S2.mp4

Я бы хотел переименовать их в HORRIBLE_HISTORIES_s01e01.mp4, где e01 взят из первого столбца. Я знаю, что хочу взять «01» из первого столбца, вставить его в переменную, а затем вставить после S2 в каждое имя файла, в то же время я хочу удалить его из начала имени файла вместе с «. _", дополнительно я хочу изменить "S2" на "s02".

Если кто-нибудь будет так любезен, не могли бы вы помочь мне написать что-нибудь с использованием awk/sed и объяснить процедуру, чтобы я мог извлечь из этого пользу?


person user3043123    schedule 26.01.2014    source источник


Ответы (6)


for f in *.mp4; do 
  echo mv "$f" \
    "$(awk -F '[._]' '{ si = sprintf("%02s", substr($5,2)); 
                          print $3 "_" $4 "_s" si "e" $1 "." $6 }' <<<"$f")"
done 
  • Зацикливается на всех *.mp4 файлах.
  • Переименовывает каждый в результат команды awk, предоставленной посредством подстановки команд ($(...)).
  • Команда awk разбивает входное имя файла на токены с помощью . или "_" (что делает первый токен доступным как $1, второй как $2, ...).
  • Во-первых, число в "_S{число}" дополняется слева до 2 цифр с помощью 0 (т. е. 0 добавляется только в том случае, если число еще не имеет 2 цифр) и сохраняется в переменной si (индекс сезона); если нормально всегда добавлять 0, "программу" awk можно упростить до: { print $3 "_" $4 "_s0" substr($5,2) "e" $1 "." $6 }
  • Результат вместе с оставшимися токенами затем перестраивается, чтобы сформировать желаемое имя файла.

Обратите внимание на echo перед mv, чтобы вы могли безопасно просмотреть результирующую команду - удалите ее, чтобы выполнить фактическое переименование.

Альтернатива: чистое bash решение с использованием регулярного выражения:

for f in *.mp4; do 
  [[ $f =~ ^([0-9]+)\._([^.]+)_S([^.]+)\.(.+)$ ]]
  echo mv "$f" \
"${BASH_REMATCH[2]}_s0${BASH_REMATCH[3]}e${BASH_REMATCH[1]}.${BASH_REMATCH[4]}"
done 
  • Использует оператор сопоставления регулярных выражений bash, =~, с группами захвата (подстроки в (...)) для сопоставления с каждым именем файла и извлечения интересующих подстрок.
  • Результаты сопоставления сохраняются в специальной переменной массива $BASH_REMATCH, где элемент 0 содержит полное совпадение, 1 содержит то, что соответствует первой группе захвата, 2 — второй и так далее.
  • Аргумент target команды mv затем собирает совпадения группы захвата в нужном порядке; обратите внимание, что в этом случае для простоты я сделал заполнение нулями s{number} безусловным - 0 просто добавляется.

Как и выше, вам нужно удалить echo перед mv, чтобы выполнить фактическое переименование.

person mklement0    schedule 26.01.2014

Обычный способ переименования нескольких файлов в соответствии с шаблоном — использование команды Perl rename. Он использует регулярные выражения Perl и является очень мощным. Используйте -n -v для проверки шаблона, не касаясь файлов:

$ rename -n -v 's/^(\d+)._(.+)_S2\.mp4/$2_s02e$1.mp4/' *.mp4
01._HORRIBLE_HISTORIES_S2.mp4 renamed as HORRIBLE_HISTORIES_s02e01.mp4
02._HORRIBLE_HISTORIES_S2.mp4 renamed as HORRIBLE_HISTORIES_s02e02.mp4

Используйте круглые скобки для захвата строк в переменные $1 (первый захват), $2 (второй захват) и т. д.:

  • ^(\d+) захватить числа в начале имени файла (в $1)
  • ._(.+)_S2\.mp4 захватить все между ._ и _S2.mp4$2)
  • $2_s02e$1.mp4 соберите ваше новое имя файла с захваченными данными, как вы хотите

Когда вы будете довольны результатом, удалите -n из команды, и она переименует все файлы по-настоящему.

rename часто доступен по умолчанию в Linux (пакет util-linux). Здесь на SO есть похожее обсуждение с более подробной информацией о поиске/установке правильной команды.

person grebneke    schedule 26.01.2014


Превратите строку имени файла в текстовый файл, затем используйте цикл и awk для переименования файла.

while read oldname; do
  newname=$(awk -F'.' '{ print substr($2, 2) "_e" $1 "." $3 }' <<< ${oldname} | \
        awk -F'_' '{ print $1 "_s0" substr($2, 2) $3 }');
  mv ${oldname} ${newname};
done<input.txt
person zhangfei    schedule 26.01.2014

Если вы хотите использовать gawk, сопоставление регулярных выражений действительно пригодится. Я нахожу это решение на основе конвейера немного лучше, чем беспокоиться о циклических конструкциях.

ls -1 | \
    gawk 'match($0, /.../, a) { printf ... | "sh" } \
    END { close("sh") }'

Для простоты чтения я заменил регулярное выражение и команду mv многоточием.

  • Строка 1 перечисляет все имена файлов в текущем каталоге, по одной строке в каждой, и передает их команде gawk.
  • Строка 2 выполняет сопоставление с регулярным выражением, присваивая захваченные группы переменной массива a. Действие преобразует это в желаемую команду с printf, которая сама передается в sh для выполнения.
  • Строка 3 закрывает оболочку, которая была неявно открыта, когда мы начали передавать в нее данные.

Затем вы просто заполняете свое регулярное выражение и синтаксис команды (заимствуя из mklement0). Например (ПРЕДУПРЕЖДЕНИЕ О ДЕЙСТВУЮЩЕМ КОДЕ):

ls -1 | \
    gawk 'match($0, /^([0-9]+)\._([^.]+)_S([^.]+)\.(.+)$/, a) { printf "mv %s %s_s0%se%s.%s\n",a[0],a[2],a[3],a[1],a[4] | "sh" } \
    END { close("sh") }'

Для предварительного просмотра этой команды (как вы и должны) вы можете просто удалить | "sh" из второй строки.

person JavadocMD    schedule 21.02.2016

с помощью АВК. переименовать файл с первой и второй и 4-й частью

ls | while read file; do newfile=`echo $file | awk -F . '{print $1 "." $2 "." $4}'`; echo $newfile;  mv $file $newfile; done;
person user1276325    schedule 04.03.2019