- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
#!/bin/bash
for i in *.root
do
if [ ! -e "$i" ] # Проверка наличия файла.
then
echo "Файл $i не найден."; echo
continue
fi
# ... etc ...
Нашли или выдавили из себя код, который нельзя назвать нормальным, на который без улыбки не взглянешь? Не торопитесь его удалять или рефакторить, — запостите его на говнокод.ру, посмеёмся вместе!
−134
#!/bin/bash
for i in *.root
do
if [ ! -e "$i" ] # Проверка наличия файла.
then
echo "Файл $i не найден."; echo
continue
fi
# ... etc ...
Не, ну а вдруг
Вообще-то ваш любимый баш в случае отсутствия .root, занесет в i строку "*.root" так то!
Скрипт искал рядом с собой tgz файлы, создавал папку с именем, полученным отрезанием расширения tgz, распаковывал туда архив, что-то там внутри обрабатывал, и удалял папку и сам архив. Все было бы красиво и безоблачно, если бы я не запустил скрипт вхолостую, без tgz файлов...
for засунул в переменную *.tgz, после отрезания расширения получилась просто *, и скрипт, с достоинством настоящего самурая, вынес свой конфиг, свой лог и самого себя :)
Эпично... Но подозреваю отсутствие двойных кавычек, некомильфо.
Впрочем, shell вообще часто радует, особенно если захотеть написать с намеком на портабельность (тот же echo -e в убунте).
Не так давно узнал, что shell-ы удаляют не только последний перевод строки, а все финальные. Забавно было получать realpath от file=$'smth\n' .
<оффтоп>Кстати кто-нибудь в курсе чем мотивируют, что glob без совпадений не возвращает пустую строку? (как всякие nullglob в bash/zsh)
Ну естественно :) Пока гром не грянет, админ кавычки не поюзает.
> тот же echo -e в убунте
А что с ним не так?
> glob без совпадений не возвращает пустую строку
Ну например запускаем cat *.dat. Сейчас он говорит cat: "*.dat: No such file or directory". А с nullglob'ом будет "зависать" (читать с stdin'а). Сменили шило на мыло...
Случайно как-то, уже не помню, по-хорошему переименовать, конечно, надо. А тут стало интересно. (А вообще частенько из *.zip кириллица валится всякая хрень.)
Внезапно, проще так: file=$'smth\n'; touch "$file" ($'\..' - башизм)
> А что с ним не так?
В dash/echo нет такой опции :) (по-крайней мере когда-то не было). http://pubs.opengroup.org/onlinepubs/009696799/utilities/echo.html :
It is not possible to use echo portably across all POSIX systems unless both -n (as the first argument) and escape sequences are omitted. The printf utility can be used portably..
(/bin/echo -е портируем в пределах gnu/coreutils, а вот встроенный - в пределах интерпретатора)
> Сменили шило на мыло...
Точно, просто почему-то я сидел на двух стульях: null - для внутренних, "" - для внешних. Но у "шила" еще один момент: литеральный "*.root" может существовать - в любом случае нужно фс дергать.
- вообще прерывать исполнение при пустом глобе. И выводить "bash: *.dat: No such file or directory", даже не запуская саму программу.
- а в for'е пусть nullglob будет всегда включен. Это, вроде как, единственное место, где допустимо и очень желательно раскрытие в ничто.
Тоже не айс: rm *.o *.old (а какие действительно есть - сразу не известно)
> желательно раскрытие в ничто
Ну конкретно для баша в массивах бы еще не помешало: arr=(*.root)
Ну по крайней мере логично написать один раз и сохранить ряд (пачку) инструкций в файл, и выполнять их.
Потом раз, стало много копипаста - нужен цикл.
Потом хочу небольшое ветвление, а то неудобно!
Потом эх! вот бы еще аргументы передавать.
Так тихо получили кашу из топораязык.
Посмотри в моем комменте ниже сниппет про файл с именем -rf. Вот отличный пример того, к чему приводит "удобство".
Кстати примерно тоже и в крестах. Отдельно от всего фича полезная, а в совокупности превращает язык в минное поле.
>ниже сниппет про файл с именем -rf
Видел. Это прекрасно.
[email protected] (Спросить Тараса)
Потому что они, как правило, очень хорошо удовлетворяют текущие потребности большинства (за счет неминуемого пиздеца в будущем, которое далеко и никого не волнует, пока не коснется их лично).
Если отойти от программирования, и взглянуть на тот же макдональдс, то мы увидим ту самую "неудачную идею с поразительной жизнеспособностью": толпы людей жрут фастфуд не думая о своем ожирении, ибо удобно ;)
Относительно баша - его можно рассматривать не как хуевую версию перла/фитона, а как хорошую - бата.
Если баш юзать не для всего подряд, то все норм ;)
> как хорошую - бата.
Ну да, как пакетный файл для примитивных задач баш хорош.
> не как хуевую версию перла/фитона
А вот для более серьезного скриптинга, когда надо прочитать какой-то файл, бегать в цикле по директориям, юзать регулярки, баш становится очень неудобным. Если не знать и не учитывать все неожиданности и подвохи - код будет дырявым бажным говном. Если учитывать - длинной некрасивой портянкой намотанной на костыли, которая на обычных языках была бы короче и наглядней.
И да, баш сложен. Изучение всех этих тонкостей всяко занимает больше времени, чем изучение того же питона, который, за исключением пары мест, туп как пробка и логичен.
В общем у всего есть своя область. И у баша это написание небольших скриптов, не требующих особой надежности, на скорую руку.
Та ну нах … даже поддержка функций есть
Из которых даже можно вернуть результат (через глобальную переменную).
(т.е. если неюниксоид смог удалить печаль, то юниксоиду бояться нечего)
Ну это потому что видел в первой строке, как создают файл. Без этого батхертов было бы больше. Как минимум пришлось бы вспоминать альтернативные способы получения списка файлов, или тупо запустить mc ;)
Я сначала выполнил ls без параметров, чтобы убедиться, что у меня создан файл -rf или --help, чтобы приступить к написанию "ls *". Всё работало без альтернативных способов.
ООП + утиная типизация в ФС. Вместе с данными (1.txt, xxx.log, ...) хранятся методы (-что-то). Для некоторых каталогов перепределены методы ls, rm и т.д.
Не получится. Все эти опции в кучу смешаются, и команды начнут выдавать ошибки о неизвестных опциях...
А насчет переопределения методов для некоторых каталогов - fuse вам в руки.
// не прыщеблядь
Звездочка раскрывается в список всех файлов, находящихся в каталоге. В результате имя файла "--checkpoint-action..." (да, в *nix'ах в именах файлов можно юзать любые символы помимо '\0' и '/') попадает в командную строку tar'а. Но т.к. автор быдлобекапилки не указал опцию -- чтобы tar понял, что дальше аргументов нет, tar парсит --checkpoint-action как опцию. Данная опция заставляет его выполнять некое действие каждый блок (10кб), в нашем случае это действие - произвольный код из evil.sh.
Вот как-то так.
Честно говоря, подозреваю что в данном конкретном случае виндовый подход лучше. Хотя бы вот таких факапов не возникает.
Еще лучше было бы если бы список файлов передавался каким-то массивом.
А вообще - достойно отдельного говнокода.
Само собой есть. Но сколько человек его юзает? :)
Как я и писал выше - кодить на баше просто и красиво ровно до тех пор, пока не требуется надежность и поддерживаемость. Иначе это геморрой с изучением тонкостей каждой команды и каждой синтаксической конструкции. Даже для простейших конструкций типа "для каждого файла в каталоге" или "заменить че-то на че-то регуляркой" нужно знать правильные идиомы.
Ну и где же эта хваленые простота и удобство баша? :)
Вот вам "портабл":
find ! -name . -prune -name '*.txt' -printf '%f\n'
А в вашем питоне glob пропустит .якобы-так-и-задумано.txt
Который ломает к хуям все остальные команды с глоббингом, и нужно включать и выключать его перед каждым фором.
> А в вашем питоне glob пропустит .якобы-так-и-задумано.txt
Вы так говорите, как-будто башевский глоббинг их не пропускает ;)
Если надо хиддены - есть os.listdir + fnmatch, о которых, даже упоминается в доке по glob. Но часто хиддены и не надо обрабатывать, они же неспроста скрыты.
> find ! -name . -prune -name '*.txt' -printf '%f\n'
Ахуеть интуитивный способ.
Я же не говорю, что в шелл скриптах невозможно что-то реализовать. Нет, вполне реально. Просто на обычных скриптовых языках это пишется быстрее, и читается лучше.
Дык и говорю: питон такой весь в белом, а как присмотришься - из посикса всякую дрянь тащит. Говорят, фича скрытых файлов возникла из за "оптимизации" ислючения "." и ".." из вывода ls.
> способ с find багует
Да вроде нет: он в зависимости от tty выводит либо "..?", либо честно, добавьте "| cat".
Вполне возможно. А ".." всяко возникла из-за "оптимизации" первых файловых систем - чтобы в качестве айдишки каталога/файла юзать только одно число, и по нему легко было бы узнавать родительский каталог.
> Да вроде нет
Ну я вот тестил for i in твойкод; do echo "[$i]"; done. Имя файла с пробелом в имени разорвало пополам. Надо или IFS менять на \n, или юзать find + exec вместо for + find. Тогда работает.
UPD: Рвет имена не с энтером, а с пробелом. А при IFS = \n начнет наоборот.
Это "как бы" весь юз-кейс был: с for-ом и print-ом.
Пизне́с, насяйника!
Даже в ДОСе таких проблем не было!
Разворачивание масок шеллом не нужно.
В ДОС это не протолкнули по счастливой случайности: длина командной строки была ограничена и больше пары десятков файлов туда бы не пролезло. В результате досовскому софту пришлось разворачивать маски, что и унаследовала Винда.
Ну объективно говоря, шелл что в досе, что в винде всегда был говном. Так что можно сказать, что прыщешелл слишком гибкий, гибкий не там где надо.
Я еле создал файл с переводом строки в имени. Пришлось привлечь к делу сишку. Откуда он вообще появился? :)
P.S. Последнее время мне приходит в голову мысль, что баш не нужен. Если его юзать не читая манов, на интуиции, то ловится куча ошибок. А если читать маны и писать аккуратно - то проще юзать какой-нибудь питон или перл: в них хотя бы логика есть, а не только исторически сложившиеся читы.
tr в помощь, можно и не такое создать, даже пустую строку можно.
* ls не покажет перенос строки в имени файла по каким-то своим соображениям, скорее всего изза форматирования.
[email protected] (Спросить Тараса)
[email protected] (Спросить Тараса)
mkdir $1
# do something
rm -rf $1/*
root@server:~ # ./test.sh
nvidia тоже когда-то неплохо потроллила юзеров примерно такой командой: