Bash regex для перейменування набору файлів


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розширення, замінене датою .

Що я спробував:

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варіант записується лише один раз на диск.

¿Що ви думаєте про ці два рішення? ...

Знову дякую.


Можливо, вони краще підходять для Unix & Linux SE .
петерф

Чи можу я перенести це питання?
Ферран

Відповіді:


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

Дякую дуже мухо Петер, але здається, це не працює так, як прописано. Я отримую таке перетворення: other-this-is-1-name-20140717-093458 Коли я шукаю: other_this-is-1-name_20140717-093458 Зверніть увагу на підкреслення після otherта перед датою.
Ферран

З невеликими змінами у програмі regex @peterph запропонуйте, і комбінуйте з іншими регулярними виразами, щоб зробити роботу. Детальнішу інформацію див. У моїй новій редакції.
Ферран

Вибачте, я недостатньо уважно прочитав питання - я оновив відповідь. Вам просто потрібно змінити роздільники навколо кореня імені файлу: просто замініть тире навколо $2накреслення в другому регулярному вираженні.
петерф
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.