4

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

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

prefix_some_name_other.txt

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

prefix_one_name_other.txt
prefix_this_is_my_name_1_this1_other.txt

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

other_one-name_datetime
other_this-is-my-name-1-this1_datetime

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

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

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

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

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

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 ответ1

2

Если ваше 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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .