Регулярное выражение Bash для переименования набора файлов

Регулярное выражение Bash для переименования набора файлов

Мне нужно переименовать набор файлов, используя renameкоманду (с регулярным выражением). После нескольких попыток я не могу найти выражение, которое даст ожидаемый результат.

У меня есть такой шаблон файла:

префикс_некоторое_имя_другой.txt

Все файлы начинаются со prefix_строки " " и заканчиваются на " _other.txt", анекоторое_имячасть может состоять из нескольких (буквенно-цифровых) слов, разделенных подчеркиваниями. Таким образом, возможно иметь:

prefix_one_name_other.txt
prefix_this_is_my_name_1_this1_other.txt

Мне нужно переименовать имена файлов следующим образом:

другой_один-имя_дата и время
other_это-мое-имя-1-это1_дата и время

Другими словами:

  • Необходимо удалить " prefix" (оставив подчеркивание)
  • Маркер " other" помещается в начало имени файла
  • Внекоторое_имя, преобразовать подчеркивание (_) в тире (-)
  • Подчеркивание в конце имени файла (посленекоторое_имя) должен оставаться
  • Необходимо удалить .txtрасширение, заменить надата и время.

Что я пробовал:

rename 's/fw_([a-z]+)_(\d)_(\w+\d)_(\w+)\.txt/$4_$1-$2-$3_'$datahora'/' *.txt

$datahoraимеетдата и времязначение (проверено). Это работает, как и ожидалось, с

prefix_name_1_gnt1_other.txt

но не с

prefix_other_name_2_gnt2_other.txt

Где я ошибся? Как еще я мог этого добиться?

Я повесил голову, так как на данный момент я не могу найти регулярное выражение, которое работает для всех имен файлов, которые у меня есть. Я знаю, что первый элемент в строке всегда является частью prefix, а последний элемент тогда является other.txtчастью строки. Так что возможно ли разбить строку на массив и получить элементы, которые мне нужны для построения нового имени. На самом деле, что-то вроде этого.

datahora="20140718-080000"
arrfiles=( *.txt )
for curfile in ${arrfiles[*]}
do
    arrparts=( ${curfile//_/ } )
    numitems=${#arrparts[*]}
    newname=""
    for (( c=1; c<numitems-1; c++ ))
    do
        newname+="${arrparts[c]}-"
    done
    newname=${newname%-}
    arrparts[numitems-1]=${arrparts[numitems-1]/.txt/}
    newname="${arrparts[numitems-1]}_${newname}_$datahora"
    echo "$curfile pasa a $newname"
    mv ${curfile} ${newname}
done

После того, как я сделал это таким образом, я еще раз попробовал предложение @peterph и, наконец, закончил с некоторыми комбинациями регулярных выражений переименования. Что-то вроде этого:

rename 's/_/-/g' *.txt
rename 's/^fw-(.*)-([^-]*)(\.txt)/$2.$1$3/' *.txt
rename 's/(\w+)\.(.*)(\.txt)/$1_$2_'$datahora'/' *.txt

Я не уверен, какой подход лучше. По-моему, вариант с регулярным выражением выглядит более элегантно, но мне нужно три операции переименования (три обращения к диску), чтобы выполнить работу, в то время как вариант arrayзаписывает на диск только один раз.

Что вы думаете об этих двух решениях?...

Еще раз спасибо.

решение1

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

Регулярные выражения, которые вы ищете, могут быть, например:

rename 's/_/-/g' *.txt
rename 's/^prefix-(.*)-([^-]*).txt$/$2_$1_'$DATETIME'/' *txt

Первый делает перевод подчеркивания в тире, а последний делает замену корня и суффикса и добавляет содержимое DATETIMEпеременной окружения к именам. И, конечно, опускает префикс и расширение.

Часть [^-]*соответствует любой строке, не содержащей тире. В случае, если суффикс всегда один и тот же, вы можете поместить его туда дословно, как в случае с префиксом (и наоборот - если префикс может меняться, используйте ^[^-]*-для сопоставления его с любой строкой, не содержащей тире, расположенной между началом имени файла и (таким образом) первым тире).

Если вы renameподдерживаете несколько команд, просто объедините их:

rename 's/_/-/g;s/^prefix-(.*)-([^-]*).txt$/$2_$1_'$DATETIME'/' *txt

Связанный контент