LINUX.ORG.RU

Как не надо писать скрипты

 


0

1

Название темы для самокритики, а дело вот в чем:
- понадобилось переименовать расширения всех мультимедийных файлов на диске с больших букв на маленькие.

Ну не нравится мне такой вид: Антонов.MP3
гораздо лучше смотрится так: Антонов.mp3

Итак задача: найти в текущем каталоге все мультимедийные файлы и переименовать их расширения из ЗАГЛАВНЫХ в прописные символы.

Начал вспоминать, какая команда в беше переименовывает файлы.
И был жутко удивлен открытием - оказывается, в могучий BASH такую команду до сих пор не завезли! :-O
Даже в убогом ДОСе она есть, а тут нет, выкручиваются костылем на основе mv.

Костылем заморачиваться не стал, а нашел приложение, которое занимается переименованием, и которое так и называется - rename
На его основе быстренько накидал «переименователь» (слабонервным просьба отвернуться :-) -

find . -depth -print0 | xargs -0 -n 1 rename -v 's|(.*\.)(BMP)$|$1\L$2|' {} \;
find . -depth -print0 | xargs -0 -n 1 rename -v 's|(.*\.)(JPG)$|$1\L$2|' {} \;
find . -depth -print0 | xargs -0 -n 1 rename -v 's|(.*\.)(JPEG)$|$1\L$2|' {} \;
find . -depth -print0 | xargs -0 -n 1 rename -v 's|(.*\.)(GIF)$|$1\L$2|' {} \;
find . -depth -print0 | xargs -0 -n 1 rename -v 's|(.*\.)(PNG)$|$1\L$2|' {} \;
find . -depth -print0 | xargs -0 -n 1 rename -v 's|(.*\.)(AVI)$|$1\L$2|' {} \;
find . -depth -print0 | xargs -0 -n 1 rename -v 's|(.*\.)(MKV)$|$1\L$2|' {} \;
find . -depth -print0 | xargs -0 -n 1 rename -v 's|(.*\.)(MOV)$|$1\L$2|' {} \;
find . -depth -print0 | xargs -0 -n 1 rename -v 's|(.*\.)(MPG)$|$1\L$2|' {} \;
find . -depth -print0 | xargs -0 -n 1 rename -v 's|(.*\.)(MKV)$|$1\L$2|' {} \;
find . -depth -print0 | xargs -0 -n 1 rename -v 's|(.*\.)(SWF)$|$1\L$2|' {} \;
find . -depth -print0 | xargs -0 -n 1 rename -v 's|(.*\.)(WEBM)$|$1\L$2|' {} \;
find . -depth -print0 | xargs -0 -n 1 rename -v 's|(.*\.)(DIVX)$|$1\L$2|' {} \;
find . -depth -print0 | xargs -0 -n 1 rename -v 's|(.*\.)(MPEG)$|$1\L$2|' {} \;
find . -depth -print0 | xargs -0 -n 1 rename -v 's|(.*\.)(MKA)$|$1\L$2|' {} \;
find . -depth -print0 | xargs -0 -n 1 rename -v 's|(.*\.)(FLV)$|$1\L$2|' {} \;
find . -depth -print0 | xargs -0 -n 1 rename -v 's|(.*\.)(FLAC)$|$1\L$2|' {} \;
find . -depth -print0 | xargs -0 -n 1 rename -v 's|(.*\.)(OGG)$|$1\L$2|' {} \;
find . -depth -print0 | xargs -0 -n 1 rename -v 's|(.*\.)(OGM)$|$1\L$2|' {} \;
find . -depth -print0 | xargs -0 -n 1 rename -v 's|(.*\.)(QT)$|$1\L$2|' {} \;
find . -depth -print0 | xargs -0 -n 1 rename -v 's|(.*\.)(TS)$|$1\L$2|' {} \;
find . -depth -print0 | xargs -0 -n 1 rename -v 's|(.*\.)(ASF)$|$1\L$2|' {} \;
find . -depth -print0 | xargs -0 -n 1 rename -v 's|(.*\.)(WMA)$|$1\L$2|' {} \;
find . -depth -print0 | xargs -0 -n 1 rename -v 's|(.*\.)(WMV)$|$1\L$2|' {} \;
find . -depth -print0 | xargs -0 -n 1 rename -v 's|(.*\.)(WAV)$|$1\L$2|' {} \;
find . -depth -print0 | xargs -0 -n 1 rename -v 's|(.*\.)(PCM)$|$1\L$2|' {} \;
find . -depth -print0 | xargs -0 -n 1 rename -v 's|(.*\.)(AAC)$|$1\L$2|' {} \;

Запустил творение и начал ждать. Однако ожидание затянулось, и оставил процесс на ночь.

Каково же было мое удивление, когда выяснилось, что за 7 часов процесс не только не завершился, а переименовал всего ... 227 найденных BMP-файлов! Т.е. до других расширений даже не добрался.

Это звездец... Начал разбираться в этом rename и насколько понял, он написан на Пёрле, который вызывается для обработки каждого найденного файла.

Тогда переделал скрипт для ускорения, точно не помню, но кажется так, дело давно было -

 /usr/bin/perl -w /usr/bin/rename -v s#(.*\.)(PNG)$#$1\L$2#
но это мало что дало, поскольку Пёрл не исправить, поэтому забросил это дело.

А как бы поступили вы, если переименовать в Bash?

★★★★★

Во-первых, в баше и команды перемещения нет. mv это внешняя программа, она не часть шелла. Вы (всмысле, не только ты, а ещё много кто) достали называть башем всё что связано со скриптами, перестаньте так делать.

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

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

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

int main(int argc, char **argv) {
  int j, verbose;
  j = 1; verbose = 0;
  if(j+2<argc && !strcmp(argv[j],"-v")) { j++; verbose = 1; }
  if(argc!=j+2) { fprintf(stderr, "Usage: %s [-v] /path/to/source /path/to/target\n", argv[0]); return -1; }
  if(rename(argv[j], argv[j+1])<0) {
    fprintf(stderr,"rename \"%s\" -> \"%s\" error %d (%s)\n", argv[j], argv[j+1], errno, strerror(errno));
    return -1;
  }
  if(verbose) printf("renamed \"%s\" -> \"%s\"\n", argv[j], argv[j+1]);
  return 0;
}

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

Разница в том что первый может неожиданно вместо перемещения начать делать copy+delete да ещё и не в новое указанное имя а в имя, неявно созданное в директории, которая указана новым именем в команде. А ещё на реализацию этого вредного поведения и парсинг соответствующих ему вариантов аргументов тратится лишнее процовое время и память.

firkax ★★★★★
()

А как бы поступили вы, если переименовать в Bash?

Nomenus-rex, например. Автор в своё время обретался на ЛОРе, сейчас ушёл, к сожалению. Но программа потихоньку развивается.

Да, это тоже отдельная программа, а не часть Баша. Настраивается конфигом.

hobbit ★★★★★
()
Последнее исправление: hobbit (всего исправлений: 2)

А что если передавать в rename не каждый найденный файл в фс (и так 27 раз), а предварительно отфильтровать список файлов грепом, попробуй выполнить замер, возможно это будет быстрее?

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

Ну я по-быстрому написал её, чего там возиться то?

Действительно. Но зачем же мелочиться? Давайте уж вместо Си сразу на Асме забабахаем :-P

А что если не 27 раз обходить всю фс, а только один, как думаешь, это не может ускорить процесс?

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

no-dashi-v2

Руки из жопы. Не так давно довелось отпарсить 3 тысячи файлов, пробежал весь цикл за 7 минут

Наоборот - это у тебя язык из жопы.
И если не звездеть попусту, как ты, то вот решение, которое на том же Пёрле обрабатывает 46844 строк за полторы секунды -

time find . -type f | rename -v 's#(.*\.)(|BMP|JPG|JPEG|GIF|PNG|AVI|MKV|MOV|MPG|MKV|SWF|WEBM|DIVX|MPEG|MKA|FLV|FLAC|OGG|OGM|QT|TS|ASF|WMA|WMV|WAV|PCM|AAC)$#$1\L$2#' >renamed_files.txt

real	0m1,640s
user	0m0,878s
sys	0m0,834s
Так что не так уж плох Пёрл - надо просто уметь его готовить :-)

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

Мне пофиг на что пофиг криворучке который не может сделать задачу, которую 25 лет назад задавали студентам в качестве лабораторной работы на 30 минут после двухнедельного знакомства с командной строкой.

no-dashi-v2 ★★
()
Ответ на: комментарий от no-dashi-v2

Если пофиг, чего ты вообще сюда влез? Хамство свое продемонстрировать на публику?
Тогда это психическое заболевание, примерное такое же, когда психопаты показывают свой отросток детям и торчат от этого.

chukcha ★★★★★
() автор топика

И был жутко удивлен открытием - оказывается, в могучий BASH такую команду до сих пор не завезли! :-O

Прямо вот люто присоединяюсь к фразе firkax про «Вы (всмысле, не только ты, а ещё много кто) достали называть башем всё что связано со скриптами, перестаньте так делать».

А так man remame мне пишет, что

RENAME(1)                                            User Commands                                           RENAME(1)

NAME
       rename - rename files

SYNOPSIS
       rename [options] expression replacement file...

DESCRIPTION
       rename  will  rename  the  specified  files  by  replacing  the first occurrence of expression in their name by
       replacement.
util-linux 2.30.2 если что.

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

Конечно же чтобы попинать тебя, что даже файлы переименовать не осилил но пафосно начал рассуждать об убогости bash, rename и других инструментов, в которых понимает чуть меньше чем ничего (например что у find есть ключи -exec и -iname).

Можно например попинать [user]firkax[/user] чья программа легко заменяется на ln && rm -f , но это уже неспортивно, ибо он хоть какой-то код написал.

no-dashi-v2 ★★
()
Последнее исправление: no-dashi-v2 (всего исправлений: 1)
Ответ на: комментарий от firkax

Твой rename как раз перловый.

Вообще-то нет:

$ file /usr/bin/rename
/usr/bin/rename: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, stripped

И я вижу util-linux-2.38/misc-utils/rename.c в тарболе.

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

когда поймешь тонкий дзен в вопросе «файл это имя или содержимое ??»

Для дзена вместо «поймешь» больше подходит «постигнешь» :=)

Знатоки, а что скажете насчет тотальной замены всех расширений на строчные буквы?
В моем примере переименованию подвергаются только мультимедийные файлы, и это безопасно.

А если подвергнуть все файлы подряд на диске (команда получится намного короче), то не получится ли так, что какие-то программы или программные компоненты перестанут работать?
Поди знай, что там на диске накопилось за 20 лет.


PS. Тут линукс, к сожалению, свое разборчивостью малые/Большие в именах файлов уступает примитивному ДОСу, в котором над этой разницей вообще думать не приходится - они равноценны, и это очень удобно.
Торвальдс уже задумывается над этим ядреным недостатком, но исправлять не торопится...


Upd.

Твой rename как раз перловый.

Вообще-то нет:

Действительно, в последних Дебианах пошла дурацкая мода прятать ходовые утилиты в кумулятивных сборках, и фиг догадаешься, в каких.
Недавно искал cfdisk, но его нигде не нет, и поиск по содержанию пакетам не срабатывает.
И лишь случайно нашел его в какой-то сборном пакете, который по названию к cfdisk не имеет никакого отношения.

chukcha ★★★★★
() автор топика
Последнее исправление: chukcha (всего исправлений: 1)
Ответ на: комментарий от no-dashi-v2

Не заменяется.

1) ln не может атомарно заменить существующий таргет на переименованный оригинал.

2) ln не сделает хардлинк на файл у которого ты не владелец (или рут)

3) ln (в линуксе и в новых бсд) не делает хардлинки директориям

4) вызов целых двух бинарников на замену одному syscall'у - фу

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

А если подвергнуть все файлы подряд на диске (команда получится намного короче), то не получится ли так, что какие-то программы или программные компоненты перестанут работать?

Нельзя, если расширение в линуксе большими буквами то оно таким и должно быть. Самое первое что приходит в голову это испортишь какие-нить исходники с асм-кодом в файлах .S. А всякое .mp3 оно системно-независимое и чисто данные - их всё равно как называть. Хотя даже тут, если ты составлял плейлист где-то из них - он сломается после переименования.

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

Вообще-то нет:

Странно, ну ладно.

И я вижу util-linux-2.38/misc-utils/rename.c в тарболе.

Я тоже вижу этот исходник в util-linux-2.33.1, при этом у меня установлен 2.36 и в нём ни бинарника ни мана к нему нет.

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

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

Согласен, тоже этого опасаюсь, поэтому не рискнул на тотальную замену.

И когда уже Торвальдс наведет с этим порядок, ведь это совсем несложно!

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

Ну этот rename вобще бесполезный. Для задачи ТС его придётся запускать (в связке с find+xargs) для каждого расширения, и всё равно он не сделает, например, такое переименование:

Photo.BMP-1.BMP -> Photo.BMP-1.bmp

mky ★★★★★
()

Каково же было мое удивление, когда выяснилось, что за 7 часов

Что-то фундаментально не так. Задача очевидно O(N), и занимать должно секунды, даже на серьёзных количествах файлов. Я в растеренности, если честно…

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

Где ты там увидел перл? Я не вижу его.

В любом случае твои фантазии - днище.

Пёрле обрабатывает 46844 строк за полторы секунды

Даже если мы в твои фантазии поверим - это нисколько. Я проверил - финд даже на днище-фс за 1.5 секунды строит список из ляма файлов. У тебя в 20 раз меньше.

В результате обработка мусорных 50к строк занимает полторы секунды. И строки там короткие. Даже если строчки килобайтные - это 30 метров/с. Т.е. даже не уровень пхп. Это совсем позорище.

Чем ты гордишься? Невежеством?

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

финд

Взоржал.

Я проверил - финд даже на днище-фс за 1.5 секунды строит список из ляма файлов.

При прочих равных всё определяется скоростью чтения с диска (пусть будет 60MB/Sec), и «разряженностью» директории.

Но, кмк, вы даже близко не понимаете как устроены более менее современные fs.

Чем ты гордишься? Невежеством?

Кто бы говорил. «Клоунадьте дальше».

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

При прочих равных всё определяется скоростью чтения с диска (пусть будет 60MB/Sec), и «разряженностью» директории.

Опять эникейские сказки меня отакуют? Ну да, расскажи мне как влияет скорость и на что. И с чего она «пусть будет» такой?

Но, кмк, вы даже близко не понимаете как устроены более менее современные fs.

Да ты чё. Какие откровения. Аргументация будет?

Кто бы говорил. «Клоунадьте дальше».

Ну да. Пришёл, нагадил и убежал. Типичная история. Конечно же ничего не будет. И он ни на что не ответит.

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

При прочих равных всё определяется скоростью чтения с диска (пусть будет 60MB/Sec), и «разряженностью» директории.

Опять эникейские сказки меня отакуют? Ну да, расскажи мне как влияет скорость и на что.

Оуеть. Да, не влияет. Ни на что. (Сарказм).

И с чего она «пусть будет» такой?

Typical consumer HDD perf. На серверном железе существенно больше.

Пришёл, нагадил и убежал.

Жду доносов. Вперёд.

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

Оуеть. Да, не влияет. Ни на что. (Сарказм).

Не, мне ненужны твои мазы. Мне нужна конкретика.

Typical consumer HDD perf.

Нет. К тому же меня мало интересуют твоё хдд. Мне нужна конкретика. Какая скорость, что я должен с ней делать. Ты мне давай, поясняй.

Для тех кто не понимает - почему персонаж теряется. Он вбросил чушь. И теперь чем больше он конкретики скажет - тем больше опозорится.

Допустим, если при вбросе 60 я бы сразу ему сказал, что эту мусорная линейная скорость, которая никому не интересна в контексте метадаты. Да, там кеширование решать какие-то проблемы, но его нет. Он про него не сказал.

Так же, никакая скорость никому не интересна в отрыве от того - сколько данных нужно читать.

При этом заметим, насколько данный персонаж опозорился. Интересна ли нам какая-то колхозная контекста, которую мы итак знаем? Нет.

А вот количество данных, паттерн доступа, эффективность обработки данных и прочее подобное - это нам интересно.

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

Сейчас вы сможете наблюдать это. Как он пойдёт гуглил ключевые слова и пастить мне всякий мусор. Ведь до вброса он ничего не знал. Кроме каких-то 60 о которых знает любая домохозяйка.

На серверном железе существенно больше.

На серверном железе. Да ты чё. Эти эникейские сказки типичные. И какой-нибудь не ноутбучный древний блин и какие-нибудь быстрые блины и какие-нибудь ссд - это всё серверное железо.

Буду знать. Каков же масштаб фантазий.

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

При этом заметим, насколько данный персонаж опозорился.

Продолжайте клоунаду.

Сейчас вы сможете наблюдать это. Как он пойдёт гуглил ключевые слова и пастить мне всякий мусор.

Вам бы мой experience в storage, ага.

Ведь до вброса он ничего не знал.

Так точно. Вбросил - и забыл.

ПыСы. Уймитесь ужо. Не смешно.

ПыПыСы. Устал я кормить тролля. Ну нах. Отдыхайте.

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

Ну вот и кончился очередной эксперт. Кстати, насколько же жалко выглядят эти оправдания. Про тролля и прочее. Прибеги, опозорься, начини рассказывать про тролля. Странное, что не начал рассказывать о том, что он там кого-то троллил.

В любом случае поведение его обусловлено эти - там ещё много интересного. Очередной персонаж бегающий за мною.

Вам бы мой experience в storage, ага.

experience у него случился.

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

Задача очевидно O(N), и занимать должно секунды, даже на серьёзных количествах файлов. Я в растеренности, если честно…

Кстати, уровень его опыта можно наблюдать здесь. Здесь типичная проблема та, на которой он засыпался выше. Скорость роста показателя не определяет его числовое значение.

Допустим, задача поиска чего-то в терабайте на блине - так же является O(n), но удачи прочитать блин за за секунды.

Самое интересное то, что автор написал о причине - у него список файлов не фильтруется до попадения в скриптуху. И если там что-то стартует на каждый элемент списка - это может длится вечность.

Ну а чё, O(n) же.

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

Очередной персонаж бегающий за мною.

Вы, мягко говоря, преувеличиваете свои заслуги. У меня есть фраза которая выражает крайнюю степень пренебрежения. Так вот. Внимание. «Я вам в рот не написаю если у вас зубы гореть будут». Аминь.

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

Очевидно, что ты будешь всё отрицать, но пруфы есть. Бегаешь? Да. Это фиксировано. Несёшь херню? Да - это фиксировано. Всё, оправдания мне не интересны.

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

А так да, меня очень волнует что там мне сообщает очередной бегающий за мною персонаж со своими обидками. Ты бы хоть старался лучше, а не просто меня чушью заспамливал. Чтобы ты хоть минимально выделялся на фоне тебе подобных.

Хотя да. Судя по всему ты пошёл другим путём. Ты хочешь тупняком обратить на себя внимание. Но это не работает. Сразу говорю.

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

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

чисто юзверский взгляд «не думать» - полностью согласен :) сильно посоветую еще не трогать сложные системы, а использовать компуткер только для просмотра ютупчика :)
кстати принесший в последствии микрософтерам много гемора. начиная с гиганстких жопных функциями по унификации маленьких/Больших букв в системе открытия файла на UTF-8, в коей могут рядом одновременно лежать файлы с именами на десятках языках и таки надо будет учитывать все варианты маленькие/Большие буковки…
и бардаками в случае многоязыковых сред.
помню в Штирлице, специальной и обалденно выручавшей виндовс-проге по подбору кодировки текста, были отдельные связки преобразований, в которых учитывалось даже преобразования регистра текста в неправильной кодировке.

ты шойто неправильно видать искал

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

ты шойто неправильно видать искал

pfg
Почему неправильно? Зачем мне лазить искать на сайте, если можно искать как положено - с помощью apt/synaptic.
И если пакет правильно собран, то найдет обязательно.
Но cfdisk фига не нашелся.

А знаете где он нашелся, и то чисто случайно, методом научного тыка?
В пакете util-linux-locales !

Вот скажите, при чем тут «locales» к cfdisk'у ??

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

Я так и сделал, когда захотел разложить фотки со смартфона по каталогам типа ГГГГ-ММ-ДД в соответствии с датой создания.

Скрипт на питоне на 10 строчек.

Я башем не пользуюсь вообще. Perl и python полностью закрывают все проблемы, причём это переносимые решения и нормальные языки с кучей батареек.

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

Да как бы и для баша полно задач, для которых он вполне подходит. Особенно если не стоит вопрос использования винды например. Просто некоторые упираются рогом - надо им на баше и всё тут. А у некоторых религиозный фанатизм не позволяет использовать питон или перл

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

если ты чегото не знаешь то это не значит что его не существует :)
есть локальная система поиска пакета по имени входящего в него файла.
apt-file search

ты точно про дебиан говоришь ??
ибо в дебиане cfdisk лежит в указанных на репозитории пакетах и более нигде.

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

apt-file search

Насколько знаю, apt-file надо доустанавливать в систему. Поэтому проще дефолтный dpkg -S file.

Знаю, т.к. в вирте с LiveCD (что-то на базе дебиана) изредка требуется найти пакет по либе/файлу.

krasnh ★★★
()