LINUX.ORG.RU

Групповое переименовывание через sed и xargs при пробелах и кавычках

 ,


0

1

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

'Bla bla bla 01 - bla bla.bla'
Есть пробелы, есть кавычки. Хочу привести к виду:
bla bla.bla
Если пытаться сделать через
ls | sed 'p;s/.*- //' | xargs -n2 mv
или
find -type bla -print0 | sed 'p;s/.*- //' | xargs -0 -n2 mv
Ругается на пробелы и кавычки. Как можно в однострочник переименовывать в подобных случаях?

PS Perl не знаю

for i in *bla* ; do
        out=$(sed "s/.*- //;s/'$//" <<<"$i")
        echo mv "$i" "$out"
done
vodz ★★★★★ ()
Ответ на: комментарий от unterwulf

Да с find-ом вообще не понятно: если переносить в текущий каталог, то — ладно, а вот если оставить в своём...

Всегда страшили такие скрипты с mv/rm. Чуть что и «Ой...». Ведь в такой однострочник проверки не сделаешь, чтобы в маску не попало что-то ненужное. Всегда казалось, что полноценный скрипт с простой вставкой защит от дурака намного правильнее рекламировать :)

Вот скажем, без кавычки последней всё равно переименует.

vodz ★★★★★ ()
Последнее исправление: vodz (всего исправлений: 1)
Ответ на: комментарий от vodz

Да с find-ом вообще не понятно: если переносить в текущий каталог, то — ладно, а вот если оставить в своём...

Не понял, в чём проблема. Насколько я могу судить, если имена каталогов не будут подпадать под sed-овские паттерны, то переименованные файлы останутся в своих же каталогах.

Всегда страшили такие скрипты с mv/rm

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

... | xargs -n2 echo mv
и проверяю глазами :-) Ещё можно mv -i, чтоб был шанс одуматься пока не поздно ;-)

Вот скажем, без кавычки последней всё равно переименует.

Так и ваш переименует. Наличие других файлов в условии не оговаривалось.

unterwulf ()
Ответ на: комментарий от vodz

Всегда страшили такие скрипты с mv/rm. Чуть что и «Ой...»

Вот для этого и нужны снапшоты.

legolegs ★★★★★ ()
Ответ на: комментарий от unterwulf

Не понял, в чём проблема.

Ну вы даёте, взяли б и протестили... sed вырезает из имени всё, до минуса+пробела.

Так и ваш переименует.

Так в том то и было возражение, что в многострочнике легко добавить всякие проверки.

vodz ★★★★★ ()
Ответ на: комментарий от vodz

sed вырезает из имени всё, до минуса+пробела.

Правда ваша. Кавычки меня заворожили и на остальное я не обратил должного внимания, потому тренернулся на файлах с пробелами и кавычками, но без минусов. Но find-то всё равно тут ни при чём, регулярку просто надо аккуратнее составить. Как вам такой вариант?

find /tmp/rename/ -type f | sed "p;s/'[^/]*- \([^/]*\)'$/\1/" | xargs -d'\n' -n2 mv

unterwulf ()
Ответ на: комментарий от unterwulf

Но find-то всё равно тут ни при чём

Да я хотел обратить внимание, что find у ТСа скорее всего только и нужен был для -print0, а для файлов ему и ls-а хватало :)

Как вам такой вариант?

А знаете ли вы, что "-d" у xargs нет в POSIX? ;)

vodz ★★★★★ ()
Последнее исправление: vodz (всего исправлений: 2)
Ответ на: комментарий от vodz

А знаете ли вы, что "-d" у xargs нет в POSIX? ;)

Я до сего дня вообще не знал, что такая опция существует. Но ваш подкол мне понятен, и только чтобы парировать, замечу, что использованная ТСом опция -0 там также отсутствует, из чего неявно следует, что соответствия POSIX не было в условии задачи :-P

unterwulf ()
Ответ на: комментарий от unterwulf

Ну да, родился xargs никому толком не нужный от отсутствия -d, так и будет ассоциироваться в связке с find, хоть там давно есть "-exec utility_name [argument ...] {} +". Правда со скобочками становится печально (доказательство - у парсера сносит крышу):

find . -name '*bla*' -type f -exec sh -c 'for i; do
    out=$(sed "s/'"'"'[^/]*- \([^/]*\)'"'"'$/\1/" <<<"$i")
    echo mv "$i" "$out"
done' . '{}' +

vodz ★★★★★ ()
Последнее исправление: vodz (всего исправлений: 2)
Ответ на: комментарий от vodz

Варианту с -exec не хватает лёгкости. Предлагаю так:

find . -name '*bla*' -type f | sed "p;s/'[^/]*- \([^/]*\)'$/\1/" | while read src; do read dst; mv "$src" "$dst"; done

unterwulf ()
for i in *.bla; do mv "${i}" "${i##*- }"; done
ashot ★★★ ()
Ответ на: комментарий от unterwulf

Варианту с -exec не хватает лёгкости.

Оно лёгкое, если б не условие с манипуляциями с амперсандами в паттерне sed-а. Ведь согласитесь, обязательный амперсанд в имени файла — это явно ошибка при создании этого архива с файлами :) Ну а главное — это, конечно, не требует каяться, что скрипт имеет ограничение - не допускает \n в имени файла. В вашем варианте лёгкость мнимая, так как два пайпа для системы совсем не лёгкость по нагрузке. Безусловно, $(cmd) — тоже пайп, лучше переписать без sed-а и сразу лёгкость появляется:

#!/bin/bash

find . -name '*bla*' -type f -exec sh -c 'for i; do
        out=${i##*- }
        echo mv "$i" "${i%/*}/${out%?}"
done' . '{}' +

Даже башизма нет, в ash заработает.

vodz ★★★★★ ()
Последнее исправление: vodz (всего исправлений: 2)
Ответ на: комментарий от vodz

Так получше, но читается всё равно туго.

Ну а главное — это, конечно, не требует каяться, что скрипт имеет ограничение - не допускает \n в имени файла

С перфекционизмом нужно бороться. Я вот борюсь. Ещё ни разу не встречал в реальной жизни файла с переводом строки в имени. Понятно, что тулы обязаны корректно обрабатывать и этот вариант, но запариваться об этом в разовых однострочниках — считаю излишним.

В вашем варианте лёгкость мнимая, так как два пайпа для системы совсем не лёгкость по нагрузке.

Я имел в виду выразительную лёгкость. Про нагрузку на систему — это уже не смешно.

unterwulf ()
Ответ на: комментарий от unterwulf

Так получше, но читается всё равно туго.
Я имел в виду выразительную лёгкость.

Я тоже. Всему есть предел, вы уже начали злоупотреблять в бла-бла. А вот уже не могу согласиться, последний вариант выразительнее вашего. Перфекционизмом тут не страдал, если б внимательно прочли код, то я специально схалтурил, поменяв амперсанд на '?', а по поводу \n в имени - оно само по себе такое, следовательно, и не напомнить не грех.

vodz ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.