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

4

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

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

prefix_ некоторое_имя  _other.txt 

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

prefix_one_name_other.txt
prefix_this_is_my_name_1_this1_other.txt

Мне нужно переименовать имена файлов, как эти:

other_one-name_ Дата и время  other_this-это-мое имя-1-this1_  Дата и время 

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

  • Надо удалить 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 Вариант записывается только один раз на диск.

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

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

Ferran
источник
Может быть лучше подходит для Unix & amp; Linux SE ,
peterph
Могу я перенести этот вопрос?
Ferran

Ответы:

2

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

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

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

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

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

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

rename 's/_/-/g;s/^prefix-(.*)-([^-]*).txt$/$2_$1_'$DATETIME'/' *txt
peterph
источник
Большое спасибо, Питер, но, похоже, все работает не так, как ожидалось. Я получаю это преобразование: other-this-is-1-name-20140717-093458 Когда я ищу: other_this-is-1-name_20140717-093458 Обратите внимание на подчеркивание после other и до даты и времени.
Ferran
С небольшими изменениями в регулярном выражении @peterph предлагаю, и объединить с другим регулярным выражением, чтобы сделать работу. Смотрите мое новое редактирование для получения дополнительной информации.
Ferran
Извините, я недостаточно внимательно прочитал вопрос - я обновил ответ. Вам просто нужно изменить разделители вокруг корня имени файла: просто замените тире вокруг $2 с подчеркиванием во втором регулярном выражении.
peterph