Когда вы автоматизируете какую-либо задачу, например, упаковываете свое приложение для Docker, то часто сталкиваетесь с написанием shell-скриптов. У вас может быть bash-скрипт для управления процессом упаковки и другой скрипт в качестве точки входа в контейнер. По мере возрастающей сложности при упаковке меняется и ваш shell-скрипт.
Все работает хорошо.
И вот однажды shell-скрипт совершает что-то совсем неправильное.
Тогда вы осознаете свою ошибку: bash, и вообще shell-скрипты, в основном, по умолчанию не работают. Если с самого начала не проявить особую осторожность, любой shell-скрипт достигнув определенного уровня сложности почти гарантированно будет глючным... а доработка функций корректности будет довольно затруднительна.
Проблема с shell-скриптами
Давайте сосредоточимся на bash в качестве конкретного примера.
Проблема №1: Ошибки не останавливают выполнение
Рассмотрим следующий shell-скрипт:
#!/bin/bash
touch newfile
cp newfil newfile2 # Deliberate typo
echo "Success"
Как вы думаете, что произойдет, когда мы его запустим?
$ bash bad1.sh
cp: cannot stat 'newfil': No such file or directory
Success
Скрипт продолжал выполняться, даже если команда завершилась неудачно! Сравните это с Python, где исключение не позволяет выполнить последующий код.
Вы можете решить эту проблему, добавив set -e
в начало shell-скрипта:
#!/bin/bash
set -e
touch newfile
cp newfil newfile2 # Deliberate typo, don't omit!
echo "Success"
А теперь:
$ bash bad1.sh
cp: cannot stat 'newfil': No such file or directory
Проблема №2: Неизвестные переменные не вызывают ошибок
Далее рассмотрим следующий скрипт, который пытается добавить каталог в переменную окружения PATH. PATH — это способ определения местоположения исполняемых файлов.
#!/bin/bash
set -e
export PATH="venv/bin:$PTH" # Typo is deliberate
ls
Когда мы его запускаем:
$ bash bad2.sh
bad2.sh: line 4: ls: command not found
Он не может найти ls, потому что мы допустили опечатку, написав $PTH вместо $PATH, при этом bash не жалуется на неизвестную переменную окружения. В Python вы получили бы исключение NameError
; на скомпилированном языке код даже не компилировался бы. В bash скрипт просто продолжает выполняться; что может пойти не так?
Решением является параметр -u
:
#!/bin/bash
set -eu
export PATH="venv/bin:$PTH" # Typo is deliberate
ls
А теперь bash нашел опечатку:
$ bash bad2.sh
bad2.sh: line 3: PTH: unbound variable
Проблема №3: Пайпы не отлавливают ошибки
Мы думали, что разобрались с неработающими командами с помощью set -e, но это не решило всех проблем:
#!/bin/bash
set -eu
nonexistentprogram | echo
echo "Success!"
и когда мы запускаем его:
$ bash bad3.sh
bad3.sh: line 3: nonexistentprogram: command not found
Success!
Решение set -o pipefail
:
#!/bin/bash
set -euo pipefail
nonexistentprogram | echo
echo "Success!"
Теперь:
$ bash bad3.sh
bad3.sh: line 3: nonexistentprogram: command not found
На данный момент мы имплементировали (большую часть) неофициального "строгого" режима bash. Но и этого все еще недостаточно.
Проблема №4: Subshells работают странно
Используя синтаксис $()
, вы можете запустить subshell (подоболочку):
#!/bin/bash
set -euo pipefail
export VAR=$(echo hello | nonexistentprogram)
echo "Success!"
Когда мы ее запустим:
$ bash bad4.sh
bad4.sh: line 3: nonexistentprogram: command not found
Success!
Что происходит? Ошибки в подоболочках не воспринимаются, если они являются частью аргументов команды. Это означает, что ошибка в подоболочке просто отбрасывается.
Единственное исключение — это непосредственная установка переменной, поэтому нам нужно написать код следующим образом:
#!/bin/bash
set -euo pipefail
VAR=$(echo hello | nonexistentprogram)
export VAR
echo "Success!"
Теперь наша программа работает правильно:
$ bash good4.sh
good4.sh: line 3: nonexistentprogram: command not found
Возможно, это достаточная демонстрация плохого поведения bash, но далеко не полная.
О некоторых нежелательных причинах для использования shell-скриптов
Каковы могут быть причины, по которым вы все равно захотите использовать shell-скрипты?
Плохая причина №1: Это всегда там есть!
Практически каждая вычислительная среда Unix имеет базовую оболочку (shell). Поэтому, если вы пишете какие-то скрипты для упаковки или запуска, возникает соблазн использовать инструмент, который уже там присутствует.
Дело в том, если вы упаковываете Python-приложение, то практически наверняка в среде разработки, CI и среде выполнения будет установлен Python. Так почему бы не использовать язык программирования, который по умолчанию обрабатывает ошибки?
По большому счету, практически каждый язык программирования с достаточно большой пользовательской базой содержит какую-то скрипт-ориентированную библиотеку или идиомы. В Rust, например, есть xshell, а также другие библиотеки. Так что в большинстве случаев вы можете использовать свой язык программирования вместо shell-скрипта.
Плохая причина №2: Просто пишите правильный код!
В теории, если вы знаете, что делаете, сохраняете концентрацию и не забываете о бойлерплейте, то можете писать правильные shell-скрипты, даже довольно сложные. А также написать юнит-тесты.
На практике:
Вы, вероятно, работаете не один; вряд ли каждый в вашей команде обладает соответствующим опытом.
Любой человек устает, отвлекается и допускает ошибки.
Почти в каждом сложном shell-скрипте, который я видел, отсутствовал вызов
set -euo pipefail
, и добавить его постфактум довольно сложно (обычно невозможно).Не помню, чтобы я когда-либо видел автоматизированный тест для shell-скрипта. Наверняка они существуют, но встречаются довольно редко.
Плохая причина №3: Shellcheck обнаружит все эти ошибки!
Если вы пишете shell-программы, shellcheck — очень полезный способ поиска ошибок. К сожалению, его одного недостаточно.
Рассмотрим следующую программу:
#!/bin/bash
echo "$(nonexistentprogram | grep foo)"
export VAR="$(nonexistentprogram | grep bar)"
cp x /nosuchdirectory/
echo "$VAR $UNKNOWN_VAR"
echo "success!"
Если мы запустим эту программу, она выдаст "success!", несмотря на то, что у нее 4 отдельные проблемы (как минимум):
$ bash bad6.sh
bad6.sh: line 2: nonexistentprogram: command not found
bad6.sh: line 3: nonexistentprogram: command not found
cp: cannot stat 'x': No such file or directory
success!
Как работает shellcheck
? Он выявляет некоторые проблемы... но не все:
Если вы запустите
shellcheck
, он укажет на наличие неполадок в export.Если вы запустите
shellcheck -o all
, чтобы запустить все проверки, он также укажет на проблему сecho "$(nonexistentprogram ...)"
. Это при условии, что вы используете версию v0.8, которая была выпущена в ноябре 2021 года. Более ранние версии не имели такой проверки, поэтому любой дистрибутив Linux, предшествующий этой версии, выдаст вамshellcheck
, который не обнаружит эту проблему.В нем не предлагается
set -euo pipefail
.
Если вы полагаетесь на shellcheck
, я настоятельно рекомендую обновиться и убедиться, что вы запускаете его с параметром -o all
.
Прекратите писать shell-скрипты
В определенных ситуациях shell-скрипты вполне уместны:
Для разовых скриптов, которые вы администрируете вручную; здесь можно обойтись методами попроще.
Иногда у вас действительно нет гарантий, что доступен другой язык программирования, и вам нужно использовать
shell
, чтобы все заработало.В достаточно простых случаях, когда требуется выполнить несколько команд последовательно, без подоболочек, условной логики или циклов, достаточно использовать
set -euo pipefail
(и обязательно используйтеshellcheck -o all
).
Как только вы обнаружите, что дополнительно делаете что-то сверх этого, начните использовать менее подверженный ошибкам язык программирования. А учитывая, что большая часть программного обеспечения имеет тенденцию со временем расти, лучше всего начинать с чего-то менее ломкого.
Материал подготовлен для будущих учащихся на курсах "Administrator Linux. Professional" и "Administrator Linux. Advanced". Всех желающих приглашаем на бесплатные demo-заняти:
«Puppet — система контроля конфигураций». На занятии будет дан обзор архитектуры puppet, его основных инструментов и методов их использования, на практике будет разобран вопрос установки, первоначальной настройки сервера и клиента, а также пример использования: настройка служб, конфигурационных файлов, установка пакетов. Регистрация
«Введение в Docker». На занятии мы рассмотрим основы контейнеризации и ее отличие от виртуализации, плавно перейдем к рассмотрению самого популярного на данный момент инструмента контейнеризации Docker — узнаем, из каких основных компонентов и сущностей он состоит, и как они взаимодействуют между собой. Регистрация
Комментарии (201)
stantum
28.03.2022 18:58+1Спасибо за хорошую подборку ошибок, будет полезна. В статье не хватает положительных примеров. Есть упоминание о питоне, еще пара слов - о "чем-то менее ломком". Конкретнее бы не мешало указать возможности.
sshikov
28.03.2022 19:06+5Дело в том, что возможностей на самом деле вагон, но: «иногда у вас действительно нет гарантий, что доступен другой язык программирования». А так как бы скрипты можно писать на чем угодно, практически, из того что у вас есть под руками. Я думаю что число подходящих так или иначе языков исчисляется десятками. Все что можно оформить как #!, сгодится. Ну вот я на груви писал — но вас уговаривать не буду, брать надо то, что вы знаете, что вам удобно.
vkni
28.03.2022 19:33Ну это же получается стек языков, вплоть до Idris'а. Для каждого размера больше подходит тот или иной язык. То есть, если брать бизнес логику, то можно
shell, python, ocaml, idris
Вместо Камла можно взять что угодно другое со статической типизацией, pattern matching и сборщиком мусора.
Основная проблема в том, что люди вместо перехода с языка на язык так и добавляют и добавляют строки в программу. В результате, программа уже выходит за рамки применимости инструмента, и получается "приехали".ganqqwerty
29.03.2022 01:01Окамл-идрис? Зачем предлагать эзотерику когда нужен максимально простой язык, заточенный под работу с файлами и пайпами? Баш и так ужасно плох от того, что значения его разнообразных скобочек и долларов сложно загуглить, а вы предлагаете какие-то языки, за которыми стоит целая философия и концепция.
0xd34df00d
29.03.2022 01:51+1Так оно предлагается ведь не для любого проекта, а в зависимости от объёма (и сложности, я бы добавил).
Трёхстрочные скрипты без особой логики — sh/bash. Простые скрипты с нетривиальной логикой — питон (ну или я на хаскеле с turtle и подобными успешно что-то делал). … Система управления реактором — условный идрис.
Ares_ekb
28.03.2022 19:23+5Проблема №4: Subshells работают странно
Для этого есть ещё один ключ -E
Я обычно использую такие настройки:
set -Eeuo pipefail
На самом деле эти ключи действительно решают многие проблемы. Наверное они обязательны для использования в скриптах.
На мой взгляд, основные проблемы с кросс-платформенностью. Начиная с того, что непонятно как лучше: /bin/bash, /usr/bin/bash, /usr/bin/env bash На Mac OS могут быть недоступны какие-нибудь команды типа readlink. Windows - это вообще отдельная история, там по хорошему все команды нужно писать в виде
call команда || exit /b 1
Плюс сложный синтаксис, который постоянно забываешь. Разница между одинарными и двойными квадратными скобками. Использование кавычек и переменных.
Но если нужен небольшой простой скрипт, то почему бы и не написать. На мой взгляд это проще чем тянуть Python или что-нибудь такое.
DDUH
28.03.2022 19:27+21Ошибок конечно приведено достаточно, но в реальности правильно написанный shell-скрипт намного лучше альтернатив на Python или чём-то другом.
siziyman
28.03.2022 22:07+7Так проблема ровно в том, что правильно писать (а также читать и поддерживать) шелл-скрипты умеет примерно никто из тех, кому реально придётся это делать.
И да, инструмент, на котором вероятность у конкретных имеющихся разработчиков допустить ошибку меньше, выгоднее в 9 случаях из 10, чем разбирать всю идиоматику работы с ещё одним инструментом (а sh и правда неимоверно проклятый во многих аспектах - и да, даже сам Стивен Борн сказал, что писать на нём что-то сложное - плохая затея в современном мире, и не надо этого делать).
elve
29.03.2022 11:22+2И предлагается тем кто неправильно писал на bash, писать неправильно на других языках (ну а если по другому не умеют пока). В чем выгода?
Как раз сейчас занимаюсь переработкой чужих пайплайнов и почему-то так выходит, что питоновский скрипт на 30 строк меняется на башевский в 5, либо вообще проще сразу на Groovy написать, чтобы сущности не плодить.
Как пример - получение токена jfog на баше это одна строка.siziyman
29.03.2022 13:11И предлагается тем кто неправильно писал на bash, писать неправильно на других языках (ну а если по другому не умеют пока).
Вы как-то ну очень in bad faith читаете то, что я написал. :)
Проблема как бы в том, что обычно хотя бы на одном другом языке человек пристойно писать умеет (если уж он программист), а шелл-скрипты - совсем нет, там на очень многие вещи надо учиться смотреть заново. А ещё знания и опыт между джавами-го-пхп на всякие там пайтон и груви переносятся просто лучше, чем на sh. Не потому, что эти языки лучше (то вопрос холиварный и в общем-то бесполезный), а потому, что друг к другу они сильно ближе, чем к sh.
почему-то так выходит, что питоновский скрипт на 30 строк меняется на башевский в 5
Если питоновский тридцатистрочный скрипт могут эффективно (т.е. без багов и с меньшими временными затратами и на чтение, и на модификацию) поддерживать 10 человек, а башевский пятистрочный - 2, то бизнесово правильным решением будет иметь 30 строк на питоне, а не 5 строк на баше.
Ни у одного известного мне программиста зарплата ни прямо, ни обратно от количества строк кода не зависит, потому не понимаю, почему это проблема. :)
либо вообще проще сразу на Groovy написать
Да ради бога! Это куда лучше с точки зрения понимания окружающими в типичном современном айти-коллективе, чем баш.
Как пример - получение токена jfog на баше это одна строка.
См. выше - не понимаю, откуда такая одержимость количеством строк. :)
elve
29.03.2022 14:28+2Проблема как бы в том, что обычно хотя бы на одном другом языке человек
пристойно писать умеет (если уж он программист), а шелл-скрипты - совсем
нет, там на очень многие вещи надо учиться смотреть заново.Если умеет, то может и проще по привычному написать. На самом деле зависит от многих условий (к примеру наличие нужно интерпретатора и всех его библиотек правильных версий на целевом сервере).
Однако давайте только посмотрим на примеры ошибок из статьи, по которым предлагается на каждую shell-команду монстрячить скрипт на языке высокого уровня, т.к. sh это "фу, бяка" =).
Человек, который пишет вот такой кодtouch newfile cp newfil newfile2 # Deliberate typo, don't omit! echo "Success"
или вот такой:
#!/bin/bash echo "$(nonexistentprogram | grep foo)" export VAR="$(nonexistentprogram | grep bar)" cp x /nosuchdirectory/ echo "$VAR $UNKNOWN_VAR" echo "success!"
и на питоне его напишет также. И на Go. И на Groovy. Но в то же время он будет называть себя программистом.
sshikov
29.03.2022 19:55Ну, я много раз переписывал с баша на груви. Не знаю, как на питоне, а у меня выходило, что груви код становился как правило сильно меньше (скажем вдвое), и попутно приобретал некие дополнительные свойства — как функциональность, так и сопровождаемость. А даже если бы он вырос как у вас до 30 строк — меня бы это, честно говоря, не сильно смутило. В таких масштабах тут не о чем говорить.
Например, у баша по сути нет модулей, подключаемых из репозитория (maven, npm, pip и т.п.). А у питона уже есть. И у груви тоже. Следовательно, ваши 30 строк питона могут подключить библиотеку, э… ну скажем pandas, и опаньки, вы резко вылезли за возможности того, что можно написать на баше, и при этом ваш код стал всего-то строк 50 содержать. А у меня, к примеру, на текущем проекте, куча вот таких вот скриптов, написанных на скале, подключающих спарк, и обрабатывающих большие данные. Как говорится, удачи, такое на баше наваять. В этом и выгода.elve
29.03.2022 22:29+1Я рад за вас, но shell-скрипты (в т.ч. sh/bash) это для перетаскивания файлов, какой-то пакетной обработки текстовых файлов и прочие примитивные действия. Автоматизация рутинных операций по администрированию системы. Ну и в нашем случае деплой или запуск сборщика. Никакой бигдатой тут и не пахнет =).
Если вам для раскладывания файлов по папкам нужно модули обязательно качать и бигдату обсчитывать, то что-то вы делаете не так.
sshikov
29.03.2022 22:55> прочие примитивные действия
Именно. Для них — ваще ни разу никаких вопросов, кроме того, что писать на баше все-таки нужно аккуратно. Как именно — ну тут об этом вся статья и куча комментариев.
> для раскладывания файлов по папкам нужно модули обязательно качать и бигдату
Не, вы немного не так поняли. Я скорее за другое. У меня есть scala в качестве баша. Ну, как у автора резонно замечено: «иногда у вас действительно нет гарантий, что доступен другой язык программирования». А если они есть — я в определенном окружении, и знаю, что у меня будет то-то и то-то, всегда в наличии.
И даже пусть у нас рутинные вполне действия — по перетаскиванию файлов, но в рамках HDFS. Ну то есть, это не бигдату для раскладывания файлов, а наоборот, раскладывание файлов для бигдаты. Операции вполне обычные, но файловая система слегка специальная, и еще надо иногда какой-то REST дернуть, или что-то еще сделать, типа SQL запрос выполнить.
И тут уже вопрос стоит чуть иначе, выбор между башем и скалой для вполне рутинных действий типа копирования и раскладывания становится иногда вполне очевидным в пользу скалы. Хотя варианты, когда все делается утилитами (и SQL, и рест, и перекладывание файлов) я тоже вижу регулярно. Ну скажем так — мне они не нравятся, и я скалу все чаще для такого выбираю. Но уж выбор инструмента, который мне или вам нравится — он вообще всегда субъективный, и зависит и от личного опыта в том числе, и тут нельзя сказать, что вообще лучше и что хуже.elve
30.03.2022 18:03С этой точки зрения согласен. Если инструмент не подходит, то натягивать сову на глобус нет никакого смысла =).
maledog
29.03.2022 11:25+2Можно подумать на python, php или golang пишут только профессионалы. Иногда откроешь код и за голову хватаешься.
siziyman
29.03.2022 13:13+3Те, кто на них пишут, с большей вероятностью напишут на питоне, грувях или го то, что поймут ещё 10 разработчиков на этих языках, чем они напишут то же самое на баше и корректно.
А так плохие разработчики конечно есть в любой экосистеме, тут вы Америку не открыли, но с этим никто и не спорит.
maledog
29.03.2022 14:32Я к тому, что если человек пишет скрипт и не задумывается о проверке результатов того или иного действия или о том что нужно объявить переменную и проверить опечатки, точно так же будет писать и на любом другом языке.
Здесь уже были не раз разборы проверки программ анализаторами кода. А пару месяцев назад я так же спорил с другими разработчиками на go по поводу того, что нехорошо передавать параметры web без проверки и санации в shell. То же самое с конкатенацией при написании SQL-запроса.
И можно подумать среди разработчиков мало знающих sh/bash/cmd/bat. Как правило с них начинают.unsignedchar
29.03.2022 14:43Для Python есть IDE, где сложно сделать совсем тупые очетяпки, типа неинициализированной переменной.
maledog
29.03.2022 14:48+1Вам же в статье написали, что в shell такое тоже возможно. Там где не удастся поработать с неинициализированной переменной всегда можно накосячить например с областью видимости или указателями.
Опять же. Есть ShellCheck.
#!/bin/bash export PATH="venv/bin:$PTH" # Typo is deliberate ls
$ shellcheck myscript Line 2: export PATH="venv/bin:$PTH" # Typo is deliberate ^-- SC2153 (info): Possible misspelling: PTH may not be assigned. Did you mean PATH? $
Или вы думаете, что ваша IDE ошибки в коде находит "волшебным образом"?
Вот моя "любимая" ошибка о которой не предупреждает компилятор:
package main import "fmt" func main() { var s []int s = append(s, 1) // ..... // ..... fmt.Println(s[1]) }
Borz
29.03.2022 14:55для Bash тоже есть IDE, который так же подсвечивает подобные ошибки
siziyman
29.03.2022 14:59+2если человек пишет скрипт и не задумывается о проверке результатов того или иного действия
Если мне не нужно какое-то прям error recovery в самом скрипте, то всё проще: я привык к поведению "есть ошибка - упадёт, будем разбираться". Потому и не задумываюсь о проверке результатов. Тот факт, что в шелле не так - один из примеров того, как разные парадигмы и изначальные предположения при дизайне языка приводят к тому, что переход с одного на другое делает очень больно.
или о том что нужно объявить переменную и проверить опечатки
Я привык писать на строго типизированных и вообще компилируемых языках, вопрос "объявить ли переменную" у меня в быту вообще не стоит. Туда же, проверить опечатки - только в литералах, если я опечатаюсь в имени переменной, код просто не скомпилится.
я так же спорил с другими разработчиками на go по поводу того, что нехорошо передавать параметры web без проверки и санации в shell.
Не очень понял, как go, web и shell в одном предложении вообще связаны все втроём, но допустим. Как я уже сказал выше - плохие разработчики есть в любой экосистеме, с этим никто не спорит. Просто переход в другую экосистему порождает новые классы ошибок связанные с тем, что язык задизайнен иначе, притом в случае с sh как раз-таки довольно радикально в некоторых местах (не-падение при ошибочном результате - это отличие, которое радикально влияет на то, как ты с каждым вызовом чего-то работаешь, да), а используется там, где последствия могут быть наоборот куда более плачевными (не экранировал переменную/путь с пробелом и удалил не то, что планировал, например), чем если косякнуть при работе с данными в памяти в других ЯП в бизнес-задачах.
И можно подумать среди разработчиков мало знающих sh/bash/cmd/bat. Как правило с них начинают.
Знают так, чтобы скопировать один файл, удалить другой и может погрепать что-то в процессе? Да, многие. Так, чтобы написать скрипт, который пакетно обрабатывает данные, сколько-нибудь активно ими манипулирует (пусть и только с извлечением нужных элементов), удаляет ровно то, что надо, корректно рекаверится/завершается, и правильно экранирует данные в любом случае? Подавляющее меньшинство.
Знаю ровно ноль людей, для которых скриптовые языки оболочек терминалов были первыми ЯП в жизни, кстати.
maledog
29.03.2022 15:38Если мне не нужно какое-то прям error recovery в самом скрипте, то всё
проще: я привык к поведению "есть ошибка - упадёт, будем разбираться".
.....
(не-падение при ошибочном результате - это отличие, которое радикально влияет на то, как ты с каждым вызовом чего-то работаешь, да)И наоборот, кому-то может понадобиться, чтобы работа была продолжена. Часто бывает, что ошибка не критичная и не стоит "паники".
Выбор shell/ЯП вопрос выбора подходящего инструмента для решения конкретной задачи.siziyman
29.03.2022 15:55+1И наоборот, кому-то может понадобиться, чтобы работа была продолжена. Часто бывает, что ошибка не критичная и не стоит "паники".
Для скрипта это, кмк, история сильно более редкая, чем обратное. Если вам нужно покопировать и помодифицировать/почитать файлы, а вы не смогли их скопировать, читать вам дальше нечего. Да и в почти любом коде можно опуститься на уровень абстракции, где вы не можете совсем игнорировать ошибку (вопрос только в том, в вашем ли коде ещё этот уровень, или уже где-то на уровне библиотек или рантайма).
Ну и да, реализовать поведение "прочитал - проверил ошибку - поигнорил" тоже стоит обычно примерно ничего, если язык инструменты обработки ошибок предлагает. А поведение по умолчанию должно быть именно тем, которое makes sense в большем количестве юзкейсов - для скриптов это как раз скорее fail-fast.
Stas911
29.03.2022 01:22+1До тех пор, пока автор его поддерживает.
maledog
29.03.2022 14:36+1Что мешает переписать? Откуда такое бережное отношение к чужому коду? Вроде "мне не ясно до конца что оно делает - лучше я не буду это трогать пока работает".
Да и на любом языке можно написать код так, что никто из знакомых с языком не поймет что оно делает. Как быть с поддержкой такого кода?
Мне например однажды встречался автор который патологически боялся битовых операций и везде заменял их математикой с числами.
Stas911
30.03.2022 03:32Внедрять coding guides и выгонять таких людей, пока не слишком поздно.
Жизнь слишком коротка, чтобы разгребать чужое г...
maledog
30.03.2022 21:34-1Тут есть тонкая грань. Зачастую не говнокодят и пишут хороший код люди, которые не способны написать ничего нового. Через некоторое время у вас в команде окажется много старательных и исполнительных людей, но вот развивать и расширять возможности продукта будет невозможно. Вы выдаете им задание на новую фичу, они старательно берутся за дело, в процессе расшибут себе лоб, несколько раз уронят готовый продукт, а результат будет крайне незначительный, зато все в красивом коде, тестах, etc...
И даже когда они будут ронять продукт, то будут искренне недоумевать, как же так? Все тестами покрыто. Все регламенты соблюдены. Все задокументировано, а упало.
Лично я считаю, что в каждой команде должен быть один "пожарный" специалист высокого класса, который применив два три грязных хака способен быстро подпереть приложение, или быстро внедрить новую фичу. Но нужен баланс, чтобы весь продукт со временем не превратился в сплошное месиво из подпорок.
Внедрять coding guides
Сам я одиночка. Но когда работал в больших компаниях по большей части "coding guides" заключалось в "форматируем табами или пробелами" или именуем функции венгерской нотацией или "верблюжатками". Но внутри соблюдая правила можно было так же говнокодить дальше. просто сопровождать все комментариями в стиле КО: func copy_file() //копируем файл.
Stas911
30.03.2022 22:15+1Мой коммент скорее относился к экстремальным случаям типа "на любом языке можно написать код так, что никто из знакомых с языком не поймет что оно делает".
xsevenbeta
29.03.2022 09:59+1С башем нужно уметь вовремя остановиться и сказать себе, что на питоне это будет работать быстрее и эффективнее (и потратит меньше времени на написание и отладку, кстати). Обожаю оба этих языка.
Cheater
28.03.2022 19:55+16Автор я думаю имел в виду sh, а не bash? Присутствие Bash никто не гарантирует. Python - тем более.
Деплой через шелл-скрипты конечно ужасен, но:
a) Дело скорее не в проблемах *sh, а в том, что использование ЛЮБОГО императивного языка для деплоя - это плохо из-за его гибкости - на шелле можно написать ВСЁ. Ровно как и на питоне и на перле и на чём угодно. Ограничить скрипты деплоя только "легальными" действиями можно только через использование декларативного языка с жёсткими ограничениями.
б) Это чудо что все юниксы хоть как-то смогли договориться о гарантии наличия штатного интерпретатора. Сколь бы плох он ни был, другого такого вряд ли будет. К попыткам зумеров сделать таковым Python я отношусь крайне отрицательно, эта зараза уже проникла в Debian, где уже многие пакеты неоправданно тянут python зависимостью. (mplayer например)
semibiotic
31.03.2022 01:11И это без учета кривой совместимости python между версиями, и его человеконенавистнического дизайна.
Am6er
28.03.2022 20:24+23Пожалуйста, прекратите писать приложения. Ведь чем сложней код - тем больше ошибок можно в нём допустить. Ну, такой себе заголовок у статьи. Вы поняли.
А вот за сам контет - спасибо. Ещё добавили бы про trap-ы, раз затронули этут тему..
siziyman
28.03.2022 22:07+1Ну вообще подход "если эту задачу можно решить без программирования, лучше так и сделать" очень часто совершенно уместный.
0xd34df00d
29.03.2022 01:52+5Пожалуйста, прекратите писать приложения. Ведь чем сложней код — тем больше ошибок можно в нём допустить.
Я больше всего радуюсь тем коммитам, где получается удалить побольше кода.
bogolt
28.03.2022 20:52+2Тогда уже перл а не питон. В нем хотя бы удобно внешние процессы вызвать, если нужно быстро склеить чуть чуть логики то всяко быстрее и удобнее получится.
mc2
29.03.2022 03:50+1Если оно у вас стабильно одной версии или очень близких. Иначе поддержка велосипеда может быть дорогой.
ophil
28.03.2022 21:28+5это совет конечно автору, а не переводчику. Вместо кучи плохих примеров дать несколько хороших. Использую в скриптах 2 принципа: streamlining и shortcircuting, посм. хорошие примеры всегда можно в /etc, раньше был специальный skeleton. Первый принцип означает вынести все проверки в начало скрипта, напр.:
#! /bin/bash -x
shortcircuting - вместо кучи if/else использовать || или && и сразу выходить с сообщением.
test $# -eq 2 || {
echo -ne "\a\n
usage: $0 month year\n
calculates number of days in the month\n
"
exit 1
}
test $1 -gt 0 -a $1 -lt 13 -a $2 -gt 0 || {
echo incorrect value of month or year
exit 1
}
echo $(cal $1 $2)|sed 's/^.* //'acmnu
28.03.2022 22:01shortcircuting - вместо кучи if/else использовать || или && и сразу выходить с сообщением.
Надеюсь вы вкурсе, что if/then/else и a && b || c не эквивалентны?
thatsme
29.03.2022 10:04+2Он, я думаю, в курсе. Тем удивительнее видеть в статье рекомендующей не использовать bash, рукожопый скриптинг без проверок.
Примеры на самом деле плохие. Это примеры уровня 2-й день изучения sh.
Alexey2005
28.03.2022 21:40+15Самый лютый ад в sh — это экранирование и работа с переменными (в частности, их подстановка). Как ни старайся, а всё равно попадётся такое имя файла, которое завалит вам весь скрипт. Такое ощущение, что оно специально задумано так, чтобы там в принципе не существовало хоть сколько-то надёжного способа заэкранировать и подставить.
legolegs
29.03.2022 00:10Как ни старайся, а всё равно попадётся такое имя файла, которое завалит вам весь скрипт.
Ну это не правда. На практике защититься от всего, кроме
\n
тривиально, а для 100% непробиваемости придётся понадобавлять-0 и т.п.
Вложенные кавычки бывают замороченными, ну так не надо их использовать. Особенно не надо использовать eval и эквивалентные конструкции. Если сложно - надо переписать просто, средства есть.
AnthonyMikh
29.03.2022 14:49+1Если сложно — надо переписать просто
… на какой-то другой язык, который не будет по умолчанию вставлять палки в колёса
thatsme
29.03.2022 17:58Можно просто за правило взять, использовать вместо обратных кавычек $() и eval, а всё что подаётся как аргумент брать в двойные (там где требуется получить значения переменных) или одинарные (когда эвалуация содержимого не требуется до передачи аргумента) кавычки.
С именами файлов ... сейчас во времена UTF-8, выдумщиков хватает. Поэтому всё что содержит имена файлов, ни в коем случае в eval сотоварищи подавать нельзя. Только использовать как аргументы и всегда как минимум в двойных кавычках.
Когда кажется что "фсё, это точно невозможно сделать!", вспомните про awk, и сгенерируйте баш скрипт им. И проверок на имена файлов можно набубенить мама не горюй ... Одна проблема: осознанно читать это смогут единицы.Отсюда вывод: если требуется реюзабл код, который необходимо мантейнить, то:
Не пишите его на баш или
Не генерируйте его.
Простые скритпы на баш, с обычными пайплайнами, без эвалуации эвалуаций, вполне можно использовать и мантейнить.
Soukhinov
29.03.2022 21:23Самый лютый ад — когда sh используется не для разработки и деплоя, а в продакшене, как часть серверного приложения, например. Тогда «завал скрипта» будет означать уязвимость и потенциальный взлом системы.
Tzimie
28.03.2022 21:46+3То ли дело CMD.exe (шутка)
andrey_ssh
29.03.2022 08:29Для кого шутка ...
а для кого способ создать серверное ПО промышленного назначения.
blind_oracle
29.03.2022 10:47Некоторые и всю бизнес-логику в SQL реализуют, но это не значит что это правильный подход...
kolu4iy
29.03.2022 13:34+1А некоторые используют фреймворки с ORM, а потом удивляются что всего на паре сотен пользователей перегруженный сервер заткнулся. Везде баланс нужен.
sshikov
29.03.2022 20:00+1Шутки шутками, а имеющийся в windows в качестве поддержки скриптовых языков WSH, в некоторой степени намного удобнее баша. А кто продолжает на cmd — ССЗБ.
Kirikekeks
28.03.2022 21:58+1set -o nounset
set -o errexit
При верной, в принципе позиции очень слабая аргументация. Вот эти два параметра - данную статью можно не писать. 1. Выход при пустой переменной 2.Выход при ошибке. При том что два экрана для шелла - это разумный предел. За шелл - быстрота написания, воспроизводимость результата (очепятки), памятка на будущее.
acmnu
28.03.2022 22:12+8По сравнению с sh, python слишком низкоуровневый. Т.е. код, эквивалентный вот такому:
zcat /var/log/nginx/access.log.2.gz | awk '$6 == "\"GET" {print $1}' | sort -un
Займет довольно много строчек, даже применяя все батарейки.
Другой вопрос, что именно бизнеслогику выражать на sh это немного кощунство из-за примитивных структур данных и плохого переиспользования кода.
unsignedchar
28.03.2022 23:11+2Python просто не для однострочников. Если в приведенной конструкции появится что-то более сложное чем plain text (xml или html, например) - на bash это станет просто ужасно. На Python - +несколько строчек.
acmnu
29.03.2022 00:22В целом согласен, но это скорее потому, что юникс сделан под плеин текст. Если бы это было не так, то баш был бы другим. Думаю он был бы похож на powershell.
К слову, в aix был бинарный реестр, древовидный. Но к нему шли довольно развитые консольные утилиты, что позволяло оперировать значениями и ветками из шела.
git-merge
29.03.2022 09:23+1Python любит ломать обратную совместимость, как всего языка в целом, так и отдельных модулей.
Написать скрипт на bash/sh - означает высокую вероятность того, что через 10 лет он будет работать.
Написать скрипт на python - означает высокую вероятность, что через 10 лет в условиях тотальной смены Python3 -> Python4 его придётся выбросить.
да и тотальная смена Python2->Python3 уже идёт несколько лет, а конца пока не видно
worldmind
29.03.2022 09:33+2Когда питон последний раз ломал обратную совместимость?
git-merge
29.03.2022 10:15-1у т.н. "батареек" это происходит постоянно
а по самому Python - до сих пор ведётся работа по миграции дистрибутивов с 2.7 на 3.
к тому моменту, как она будет закончена, начнётся миграция с 3.X на 4.
bash скрипты написанные 10 лет назад преимущественно работают нормально
python-системные скрипты за 10 лет, преимущественно переписаны из за обратной несовместимости
Какой-либо язык можно предлагать на замену bash, но точно не python. У Python слишком подмоченная репутация
worldmind
29.03.2022 10:55+2Не могу сказать что вы ответили на мой вопрос.
Какие ещё дистрибутивы ведут миграцию? Даже в дебиан давно третий питон по дефолту.
andrey_ssh
29.03.2022 11:34+3В Debian 11
>python
... команда не найдена
python 3 запускается командой
>python3
в Debian 9
>python
вызывает python 2.7
Таким образом, есть возможность, что скрипт на питоне сломается ещё не запустившись.
siziyman
29.03.2022 15:08Написать скрипт на bash/sh - означает высокую вероятность того, что через 10 лет он будет работать.
Главное, не дай бог, в другое окружение его не переносить, а то потом затрахаетесь считать, где разные имплементации шеллов в ногу стреляют, где какой утилиты нет, на которую вы завязались...
vvzvlad
29.03.2022 18:14Вот только он сломает это довольно аккуратно, с четкими и понятными описаниями изменений. Небольшие скрипты переделываются со второго питона на третий эдак за полчаса гугления ошибок. И судя по тому, как поддерживается второй питон, третий десяток лет тоже протянет.
Баш любит ломаться просто при смене окружения. Завтра захотите перейти на другой дистрибутив, и все, ищите где у вас в какой утилите ключ теперь по-другому вызывается.
RiaD
29.03.2022 09:10+1from plumbum.cmd import zcat, awk, sort (zcat['/var/log/nginx/access.log.2.gz'] | awk ['$6 == ""GET" {print $1}'] | sort ['-u', '-n']) & FG
как-то так. И уже пробелы в названия файла не страшны..
acmnu
30.03.2022 10:10Да, про эту штуку я уже читал, но меня она немного подбешивает. Мне не нравится, что в python втащили синтаксис bash, перегрузив привычные операторы (если я правильно понял как оно устроено).
Т.е. синтаксис как бы разваливается на две части: обычный питон, и питон с магией.
Я бы предпочел более привычную для python историю. Что-то типа
zcat("access.log.2.gz").awk('$6 == "\"GET" {print $1}').sort(uniq=true, number=true)
И да, такое можно сделать и даже вроде как не сложно, но сила привычки велика.
F0iL
28.03.2022 23:38+3Как писать bash-скрипты надежно и безопасно: минимальный шаблон. Не панацея, но мне в свое время оказалось весьма полезным.
Goupil
29.03.2022 00:10Спасибо, дай бог мне тоже пригодится. У меня всякий раз когда нужда писать на баше экзистенциальный ужас.
JPEGEC
29.03.2022 02:02+2Если заглянуть практически в любой шелл скрипт системы, то мы увидим многочисленные проверки существования, файлов, каталогов, программ. Снимающие практически все озвученные автором "проблемы".
Не верю что автор об этом не знает.
PS Как язык bash конечно так себе. Но это совершенно не повод везде и всюду пытаться совать python. Всякому овощу свое время и место.
ckpunT
29.03.2022 06:29Название статьи должно содержать слова: "Пожалуйста" "пишите" "shell-скрипты" "правильно"
vasilisc
29.03.2022 06:59+6Извините меня админа, но топорные bash скрипты автоматизации работают годами. Нет ни времени ни желания при выходе новой версии того же Питона переписывать код вчера с 2 на 3 версию, а завтра с 3 на 4 и т.д.
Physmatik
29.03.2022 22:34А глобальные версии питона живут десятилетиями, а не годами. И кто тогда, спрашивается, имеет преимущество?
vasilisc
30.03.2022 09:10bash =)
У меня есть скрипты с 2004 года, а это уже почти 20 лет и там не нужен Питон от слова совсем. Bash - это прежде всего простота и быстрая возможность изменить/добавить. В консоли сервера в редакторах вы ещё настраиваете замену tab на череду пробелов, чтобы не сломать python скрипт (возможно не ваш), а я уже поправил свой bash скрипт и он снова в строю.
unsignedchar
30.03.2022 09:16Так себе практика - править чего то исполняемого в консоли сервера. Python/bash - неважно.
vasilisc
30.03.2022 10:47Не во всех конторах серверов столько что обязательны инструменты оркестровки типа ansible, а перед этим Git, череда тестов и CI/CD. Много админов используют лишь SSH и работу на сервере при проблемах или в случаях каких-либо изменений.
N-Cube
29.03.2022 07:14-1Все же шеллы (баш, даш и прочие) не просто так задуманы с продолжением работы после ошибки. Типичный ход выполнения это серия команд, после которой проверяется наличие результата - и здесь уже можно выйти с ошибкой или повторить обработку при необходимости. Проверять же результат выполнения каждой внешней команды зачастую просто бессмысленно, а сообщения об ошибках подкоманд будут выведены в консоль по умолчанию (если только мы не скрыли их намеренно). Питон и подобные языки просто не рассчитаны на работу в непредсказуемом окружении, когда и права доступа на используемые файлы могут измениться в процессе работы, каталоги и файлы исчезнуть, закончится место на диске, упадет по таймаутам все что только может и так далее - так что никакие проверки не дают гарантии успешного выполнения кода.
Vitaly83vvp
29.03.2022 07:42Если неуметь писать код, то результат будет попахивать независимо от языка. В приведённых примерах нет проверок и, конечно, это может вызывать ошибки. Тоже самое произойдёт при работе с другими языками. Для меня bash - достаточно удобный инструмент работы. Но, если воспринимать его как нечто тупо вызывающее другие команды, то можно напороться на ошибки. Тут можно проверять значения переменных, наличие файла, результат работы программы. И это только самое простое, что поможет написать скрипт уровнем выше. А если почитать документацию, то будет ещё интереснее.
aml
29.03.2022 08:26+1В общем суть статьи: обработка ошибок в шелле по умолчанию не подходит для задач типа CI/CD (где действительно обычно лучше упасть, если хоть что-то пошло не так), и не забудьте делать вот так.
vaniacer
29.03.2022 08:32-1Вы меня убедили, ухожу на покой и удаляю все свои репы. Клонируйте пока
github не прикрылиможно: piu-piu, sshto, kube-dialog
myx_ostankin
29.03.2022 09:11-1Простите, а что мешает использовать ShellCheck, который ловит вроде бы абсолютно все вышеперечисленные проблемы?
deadfish45
29.03.2022 09:20+4Мне кажется что если кодер допускает вот такую ошибку
cp newfil newfile2 # Deliberate typo echo "Success"
то python не поможет. Здесь человек явно хочет вывести "Успех", вне зависимости от результата оперции. С операцией копированния, казалось бы очень простой, много что может пойти не так, на некоторые проблемы питон может выдать эксепшин, а на некоторые нет. Так у пользователя может не быть доступа на чтение к файлу источнику или на запись к фйалу/директории назначения, на носителе может закончиться место, может закончиться виртаульная память, и т.д. Все эти ошибки ловятся и питоном и простой проверкой успешности выполнения команды cp, например через переменную "$?" . Но если newfile2 уже существует и является директорией, то файл скопируется в директорию, cp завершится успехом, вряд ли это тот результат который ожидал автор скрипта. Если файл источник уже сещуствует и является пайпом, тогда touch не возымеет эффекта, а копированние зависнет на блокующем read, и выполнение копированния не закончится пока процессу не придёт сигнал, или пайп не откроет на чтение и закроет, другой процесс. У sh есть свои преимущества, сильные стороны из-за которых им и пользуются, его даже необходимым злом не назвать, если ты порезал руку ножом это повод задумываться о том, чтобы перестать им пользоваться? Статью с таким же успехом можно было назвать "Пожалуйста, прекратите писать какие бы то ни было скрипты или программы, если вы не являетесь экспертом, с нечеловеческой способностью держать все факторы в голове и не допускать ошибок".
Physmatik
29.03.2022 22:41Подставьте вместо
echo "Success"
любую операцию сnewfile2
.Приведённый пример — именно что пример, единственная задача которого состоит в максимально лаконичной демонстрации проблемы.
edo1h
30.03.2022 01:23Подставьте вместо
echo "Success"
любую операцию сnewfile2
ну вот когда подставится, тогда и надо делать обработку ошибок. что в баше, что в питоне.
и падение с нечитаемым stack trace — это не сильная сторона питона, а его проклятие. постоянно сталкиваюсь прогоняя скрипты ansible, например.P. S. вот реальный init с одного проекта:
#!/bin/sh /usr/sbin/nft -f /etc/nftables.conf /sbin/sysctl -p /etc/sysctl.conf exec /usr/bin/runsvdir /sv
где мне тут нужно падение скрипта в случае ошибок и зачем?
и зачем мне в проекте, где образ системы пять мегабайт (ну ладно, 10 с ядром и бутлоадером), в разы более жирный питон?Physmatik
30.03.2022 02:34А вы совет "часто мойте руки" тоже так воспринимаете, моя руки буквально после каждого чиха? Или всё же понимаете, что советы дают без приписки "делать во 100% случаев во всех возможных существующих юзкейсах", ибо каждый случай уникален и люди тем и отличаются от машин, что умеют глубоко понимать контекст?
Если у вас система 5МБ, то, разумеется, никаких питонов тащить не надо. Но система в 5МБ — это, мягко говоря, не совсем частый случай. Обычно люди пишут баш-скрипты под самые обычные дистрибутивы типа дебианов и сентосов, где питон уже есть. Да и "питон" пишут чисто для примера, можете брать перл или TCL. Смысл статьи в том, что:
- Падение при первой ошибке (и другие ключи) гораздо чаще сохранят вам нервы, чем нет. Разумеется вы, как разумный и понимающий контекст человек, можете эти ключи не использовать, если они будут противоречить логике скрипта.
- Использование более строгого скриптового языка общего назначения (НАПРИМЕР, питона) в среднем сильно облегчит как дебаг, так и последующее чтение вашего кода, который на баше слишком часто write-only.
Но вы влазите со своим очевидно нестандартным юзкейсом в виде системы на 5МБ и начинаете доказывать, что вся статья — хрень, ибо вам конкретно не подходит. Неужто сами не понимаете, в чём проблема?
edo1h
30.03.2022 10:53Но вы влазите со своим очевидно нестандартным юзкейсом
я влезаю со стандартным use case: скрипт на несколько строчек, в котором обработка ошибок или не нужна, или нужна в паре мест.
с тем, что если скрипт не помещается на экране, то нужно плотно подумать над тем, чтобы переписать его с sh/bash на другой язык, я полностью согласен, но в статье было написано совсем не это.
vvzvlad
30.03.2022 11:04я влезаю со стандартным use case: скрипт на несколько строчек, в котором обработка ошибок или не нужна, или нужна в паре мест.
И совершенно игнорируете то, что уже в десятке мест в комментариях сказали «для скрипта в пять строчек консольных команд, выполняемых друг за дружкой питон не нужен», да? Давайте я еще раз тут скажу: в этом случае питон не нужен, оставьте баш, никто вас ругать не будет, разрешение от комьюнити на использование баша получено, честно-честно.
mawinist
29.03.2022 09:22+1bash или тем более sh есть в любом окружение unix подобном... В любом самом урезанном контейнере, а вот тот же питон нет. К тому же как по мне сравнивать python и более старый и простой bash явно не стоит, питон естесно выграет по функциональности т.к. является ЯП общего назначения в отличии от баш.
itded
29.03.2022 09:23+2Пока shell и powershell скриптов мне хватало за глазы, отладка и тестирование вам в помощь. Хотелось бы перейти на python или go, курсы по которым я прошёл, но когда смотришь на задачу и понимаешь, что ее можно решить sed и awk, сложно заставить себя вспоминать типы переменных и функции
worldmind
29.03.2022 09:31Да, как раз такой статьи не хватало когда я писал заметку про питонную замену шелла - xonsh
13werwolf13
29.03.2022 10:20+2у автора видимо почасовая оплата, ну или оплата по кол-ву символов.
простые задачи которые обычно решаются баш скриптом в десяток строк на питоне пишется дольше и выходит толше, а результат один
все указанным проблемам автор сам и привёл решения. а нагавнокодить можно на любом языке. если же всё оттестировать и по сто раз перепроверить то скрипты в проде вполне себе имеют право на существование.
siziyman
29.03.2022 13:15+1на питоне пишется дольше и выходит толше, а результат один
если же всё оттестировать и по сто раз перепроверить
Так в том и дело, что большинству разработчиков сделать это с питоном/груви будет проще, чем с башем.
13werwolf13
29.03.2022 13:16-1ни разу не видел в работе (на личных тачках не считается) у разработчиков shell скрипты. только у админов и девопсов
siziyman
29.03.2022 13:19Не у всех и не всегда выделенные девопсы под каждый чих есть, во-первых.
Во-вторых, вот он я разработчик (за последние годы писал на го, джаве, скале и котлине), на двух из трёх последних мест работы я писал скриптики шелловые.
merlin-vrn
29.03.2022 10:35+3А почему вместо Bash — Python, а не TCL? Уж не потому ли, что автор про него не знает? Озвученных "недостатков" bash у него нет. Главное, это Tool Command Language — он специально предназначен для таких задач, которые часто решают Bash-скриптам
Гораздо легче пайтона, перла - взамен баша годится получше. Достаточно компактный и переносимый, легко писать для него собственные расширения (если уж приспичит). Именно он встроен в Cisco IOS для кастомной автоматизации. Событийная модель и работа с сокетами у него эталонная, если кто-то думает что это в [подставь свой любимый язык] изобрели, вы скорее всего ошибаетесь. Есть и shell, причём он работает вместе с событийным приложением, например, оконным (Tk) — можно при отладке в процессе работы приложения в шелле менять значения переменных, заменять обработчики и т. п. Кстати, Tk, SQLite и некоторые другие проекты изначально задумывались именно как дополнения к TCL, а уж потом обрели (относительно) самостоятельную жизнь.
acmnu
30.03.2022 10:00Ну в мире много интересных систем, которые не стали распространнеными. И не смотря на то, что TCL хорош, но по распространенности до bash и python ему невероятно далеко.
johnfound
29.03.2022 15:11+2Все говорят, что bash нельзя, Все говорят, что bash нельзя, Все говорят, что bash нельзя, А я говорю, что буду.
asnow
29.03.2022 15:58Из разряда не делай это потому что ты не умеешь это готовить. sh хороший инструмент, с чего это вдруг его нельзя использовать. Ок то что вы только python знаете это как бы не проблема сообщества. Да sh имеет много нюансов, я и сам не супер хорошо его знаю. Но для этого и есть манулы и учебники. Если в задаче у тебя есть требования только на unix среду то тут сразу вопрос встанет ли ваш python или ещё какая приблуда в физических ограничениях заказчика
Alexander_The_Great
29.03.2022 19:30>на скомпилированном языке код даже не компилировался бы.
Либо статью писали с телефона (спасибо, что не с электронной книги), либо студет тупо прогнал зарубежную статью через гуглотранслейтор, который уже очень хорошо (для машины) научился в перевод технических текстов.
ALiEN175
30.03.2022 00:44+1Бред какой-то. Пожалуйста, прекратите писать shell-скрипты — а итоге и в shell не сумели. Точно такой же говнокод я могу и на питоне, и на ждаве и на го организовать. У автора какая-то личная неприязнь к языку командного интерпретатора. И вот прям капсом — SHELL НЕ ЯЗЫК ПРОГРАММИРОВАНИЯ!
Проблема №1: Ошибки не останавливают выполнение
А кто вам сказал, что ошибки ДОЛЖНЫ останавливать весь скрипт? Одна строка — одна команда.
Проблема №2: Неизвестные переменные не вызывают ошибок
Что написали, что и получили. Нет $PTH — получите — "".
Проблема №3: Пайпы не отлавливают ошибки
см. Проблема №1
Проблема №4: Subshells работают странно
Работают так, как должны. Можете считать контейнером, если так понятнее.
garbagecollected
30.03.2022 03:29Про grep, rsync уже сказали. Про git, diff, dd пока молчали.
Хорошо, когда мне надо сделать миллион папок, например, так чтобы было три уровня вложенности:
mkdir -p ./{00..99}/{00..99}/{00..99}
Как такое сделаете на пресловутом python? - Сами используйте свои циклы наздоровье!
Или, например, если мне нужно скачать 1000 файлов при разрешенных сервером 10 одновременных соединений:
cat ./urls.txt | xargs -L1 -P10 wget
Как вы будете реализовывать такую очередь на python? - Какую именно реализацию Queue выбрать?
Вдруг мне захотелось псевдо UI:
dialog --yesno "Are you sure?" 5 17
Что там есть у python? ncurses и blessed? - Нет уж, спасибо!
Автор упоминает о shellcheck, а вот про существование morbig он не в курсе. Наверное, Роскомнадзор заблокировал Google.
Ах, если б не этот bash, никто бы бед не знал. Прям камень предкновения. Да! Давайте заменим bash на python, systemd на docker, vim на PyCharm, электронную почту на Discord, ssh на TeamViewer, Google.Play на pacman из ArchLinux. И да настанет процветание! - Нет, не настанет.
Лучше б действительно написали статью о том, как включить docker в сборку ядра, что бы ядро не выросло за пределы условных 50Мб при простеньком gzip-сжатии.
P.S. я и сам не в восторге от bash, и везде заменяю его на fish. Но это же вкусовщина! А что делать любителям zsh на MacOS? Там нет этих проблем? Тоже переходить на docker?
unsignedchar
30.03.2022 07:38Однострочники из ваших примеров переписывать нет смысла ни на каком языке. Они и так хороши. Правда, они напрочь синтетические ;) Любое изменения условий, и это уже не однострочник, а неприятного вида портянка.
edo1h
30.03.2022 10:56Правда, они напрочь синтетические
странно, а у меня полно таких однострочников.
iwram
30.03.2022 08:12-1Знаю людей, которые до сих пор убеждены, что все новые технологии - это обёртка надо bash. Везде алгоритмы и последовательности, значит это баш. :)
lumag
30.03.2022 11:23+2Пожалуйста, прекратите писать скрипты на Bash. Это так себе идея. Чем дальше, тем чаще приходится писать на чистом (POSIX) sh. Минус bash-измы, зато возрастает переносимость скриптов. Различия, в целом, минимальны.
edo1h
30.03.2022 13:20+1что различия минимальны не соглашусь, где, например, hash-таблицы в posix shell.
но у меня под рукой полно систем с busybox, докер-контейнеров без bash, так что за совет по возможности использовать posix shell я голосую обеими руками.
ну а если возможностей posix shell недостаточно, то действительно стоит задуматься о переходе на «настоящий» ЯВУ
Burunduk73
31.03.2022 13:09Пожалуйста, прекратите втюхивать недоязык питон!
Кому не хватает возможностей баш, прочитайте к нему инструкцию, ну, или учите яву, но это совсем другая история, куда питонистам лучше не заглядывать, чтобы не стало больно за бесцельно прожитые годы)
amkartashov
альтернативы какие?
vvzvlad
Написано же: Python, например.
amkartashov
bash - это не только дерьмовый язык программирования, но и универсальный удобный клей для консольных утилит. С любым другим языком либо придётся переписывать curl/sed/cat и сотни других мелких утилит, либо обмазываться popen'ами и exec'ами.
ultrabloxx
Не придётся. Для Python есть библиотека plumbum, которая не просто позволяет писать клей практически с башевской семантикой, но и позволяет это делать кроссплатформенно (например, на Windows тоже работает), или даже через SSH-соединение. Причём можно произвольно chain'ить как локальные, так и ремоутные команды, не парясь с тем, как экранировать аргументы ssh, чтобы сделать на ремоуте только то, что нужно.
https://plumbum.readthedocs.io/en/latest/
amkartashov
Это клёво, возьму на заметку. Какие (пред)вижу проблемы:
надо будет pip, которым будем засорять систему (неактуально для CI/CD и других систем, где используются короткоживущие окружения)
придётся доверять этому пакету (раньше доверяли bash'у из пакетов вендора)
не уверен, что pip пакет нельзя подменить, (решается проверкой чексум)
ultrabloxx
Ну, вопрос доверия можно решить только аудитом фиксированной версии. В целом, разработчик (Tomer Filiba) достаточно известный, и помимо Plumbum у него есть много других заслуг (например, RPyC, протокол и библиотека для исполнения Python-кода на remote-серверах, например, для автотестирования или распараллеливания программ).
В целом, если высокие требования к security - то pip-репозиторий можно поднять локально, во внутренней сети, и не брать пакеты из PyPI. И залить туда фиксированную версию, прошедшую аудит. Это решит проблему подмены пакетов.
А если использование pip вообще нежелательно - то в принципе, установленный plumbum можно просто заархивировать, и распаковывать в site-packages питона в каждом окружении, где он нужен - насколько я помню, он написан на чистом питоне, без сишных extension'ов, так что там не нужны никакие post-install скрипты, и поэтому ставить через pip его не обязательно.
ShadF0x
Судя по репозиторию проекта на GitHub, там уже всё сделано так, что можно собрать самому через "python -m build", поэтому даже PyPI не нужен.
ganqqwerty
Я вот часто сталкиваюсь с ситуацией когда разные линуксы и например osx имеют чуточку другую версию консольных утилит, и в них нет какого-нибудь страшно важного ключа.
Не слышали про то, как можно это заранее проверить при написании скрипта, или хотя бы уж сгененировать для скрипта описание типа package.json?
amkartashov
bash - головная боль, да. Это не отменяет его универсальности и большинство этих проблем освещено в SO.
igrishaev
Серьезно? У меня образ alpine в 5 мегабайт. Прикажете тащить за собой 150 мегабайт питона? Уж если на то пошло, баш-скрипт можно сгенерировать из Питона или другого языка. Но заменять баш Питоном это адский оверхед.
kingleonfromafrica
Не все для калькуляторов кодят. Мне и большинству моих коллег даже 1,5Гб по большому счету вообще ни чего не изменит.
igrishaev
Кроме размера, увеличится время сборки образа. Если у вас образ кафки или кассандры, то установка туда питона это лишний шаг + несколько минут установки. Короче, хрень. Плюс питончику на любой чих нужно вирутальное окружение, менеджер пакетов и прочее барахло. Словом, нужен банан, а получили джунгли впридачу.
vvzvlad
Вопрос в том, какая цена поддержки баша, и не выше ли она чем накладные расходы на эти 150мб. Виртуальное окружение и менеджер пакетов не всегда нужны, прекрасно можно собрать интерпретатор и десяток библиотек без всего этого, просто скачав их при сборке образа.
Если у вас на баше скрипты в пять строк, то «уйди, мальчик, не мешай», конечно, никакого плюса при внедрении питона вы не получите. Если у вас образ в продакшене в пять мегабайт, то да, добавление питона его сильно раздует (не уверен, правда, зачем может потребоваться образ в 5мб, но ладно).
Но не проецируйте свою ситуацию на всех, пожалуйста, объявляя такое использование питона «ненужной хренью».
i9i6
если не скрипты в 5 строк - не проще ли тогда писать на настоящем яп? без утягивания за собой всего мира?
vvzvlad
А у вас среднего не бывает, да? Или пять строк, или «настоящие» яп. 20 строк, как, требуют уже «настоящего» яп? А 50? А если это 50 строк, но с кучей передающихся туда-сюда значений?
Мир за собой никто не утягивает. Но и соглашаться с тезисом «уйдите со своим питоном, это же ЦЕЛЫЕ МЕГАБАЙТЫ кода ему требуются», я тоже не собираюсь. Просто потому, что мир не черно-белый, он градиентом:
Есть задачи, для которых питон излишен: сделать пайплайн уровня «cat|grep|awk>temp.txt» проще, действительно, на баше.
Есть задачи, которые не надо делать на баше: например, какой-нибудь простой супервизор с веб-апи и sqlite. Можно, но не надо. Любой вменяемый разработчик тут возьмет джаву/питон/плюсы/етс.
А вот между двумя этими классами есть куча задач, которые можно с равным успехом реализовать и на питоне, и на баше (в плане того, что они будут работать и их можно написать за сравнимое время), но вот решение на питоне будет проще, логичнее, поддерживаемее и проще в сопровождении.
Именно на эти задачи нацелена статья, которая говорит «ну прекратите пристраивать баш куда ни попадя просто потому что он есть по-умолчанию, возьмите нормальный язык, не экономьте десяток мегабайт».
isden
А я еще помню всю ту боль, когда для таких задач было модно использовать перл.
12rbah
khajiit
Смысл этой штуковины: работать в хуке пакетного менеджера. Активная работа с файлами и разделами, вычленение esp на зеркалированном пуле, перемещение указанного файла в указанную папку, контроль "населенности" esp и опциональная сортировка оставшегося. Работа в связке с другими модулями — через переменные окружения.
А заодно: как просто будет в реализованном разобраться…
AnthonyMikh
Я вот не могу разобраться в том, что привели вы.
khajiit
Это кусок хука, отвечающий за доставку payload (file or directory) в заранее заданные ESP или расположенные на тех же дисках, что и ZFS-пул. Обычно вызывается после регенерации initramfs, но также после создания/удаления клона, добавления ядер, и т.д.
Тасклист у него простой: проверить валидность параметров, дополнить и развернуть умолчания, найти список ESP, далее с каждым: примонтировать, выгрузить payload, проверить переполнение, отмонтировать, опционально отсортировать (именно после отмонтирования).
В этом экземпляре неправильная проверка (
-n
вместо-z
) в паре мест.Поскольку это хук пакетного менеджера, то интерпретируемые языки отпадают сразу: они могут сломаться в процессе обновления.
ShadF0x
Дедовские
FlyHighOnTheSky
Гугл относительно недавно представил https://github.com/google/zx
xmcuz
Go. Серьёзно!
Обратная совместимость и есть во всех репозиториях.
Очень простой и легко читаемый синтаксис. На порядок проще чем bash.
Очень быстра компиляция, благодаря чему можно работать как с башем.
Задачи по обработке больших массивов данных
логовщелкается как семечки. В тысячи раз быстрее чем баш.git-merge
4.
где используется bash скорость не важна2.
типизация мешает сильноXop
Забыли еще добавить, что бинари как правило без зависимостей на системные либы, что тоже очень удобно
StraNNicK
выше в комментариях было уже, но повторюсь — как в go со склейкой нескольких консольных утилит?
Ну, т.е. реальный пример баш скрипта:
1. curl с авторизацией и сохранением cookie;
2. curl с выкачиванием страницы, используя cookie из п.1;
3. множественный grep по результату, с сохранением полученных данных в переменные;
4. формирование html файла из переменных;
5. rsync полученного html на удалённый сервер по ssh.
Я просто не знаю как с этим в go, интересно.
unsignedchar
Даже не видел, как это сделано, но уже хочется плакать ;)
StraNNicK
да, приличные люди делают такое в Python, например.
но в баше это в буквальном смысле 10 примитивных строчек, тем и подкупает.
siziyman
В баше это write-only код, в питоне, при всей моей к нему нелюбви, это хотя бы разобрать можно будет.
khajiit
Write-only это регулярки… Bash неплохо читается, да и всегда можно проверить, что выполняется.
Eugeeny
Типичная ошибка - думать, что зачем-то вообще надо вызывать curl в других языках - что в питоне, что в го все это делается напрямую.
Edit: одна из больших проблем людей, пересаживающихся с баша - неспособность отличить то, что ты хочешь (intent) от того, как ты это делаешь (means) - в основном из-за отсутствия опыта в других языках. Людям не приходит в голову, что вызов curl/cat/cut/awk - это не цель, а костыль.
StraNNicK
Так вы сейчас ровно ту же ошибку мышления демонстрируете.
Я описал именно так, чтобы продемонстрировать — вот, мы скачиваем страницу, требующую авторизации, вот мы из неё что-то выкусываем, из этого чего-то формируем нечто другое и отправляем на удалённый сервер по ssh. Но вы увидели только curl.
Ок, curl не нужен, а как быть с остальным? Вероятно grep тоже не нужен, а вот с rsync как?
Я собственно и спросил — как такое делается в go?
Eugeeny
На go никогда не писал, но предполагаю что так? https://pkg.go.dev/github.com/pkg/sftp#example-package
На питоне "без батареек" это тоже не выйдет - ssh-клиент это отдельная либа (Paramiko), но все остальное (скачать, разобрать (нормально, а не grep), сформировать) - делается нативно
StraNNicK
звучит логично, спасибо.
amkartashov
intent - запускать curl/sed/awk. Скриптописатель пишет скрипт (сценарий) запуска консольных утилит, а не сами утилиты.
Если вы думаете, что вы вдруг напишите curl на go лучше авторов curl - да пожалуйста. Только curl - это одна утилита из тысяч.
siziyman
Если человек решает задачи исключительно в терминах "запустить команду/утилиту Х", он профнепригоден, извините. Задача - "извлечь данные с веб-страницы и сохранить их куда-то". Решаются они средствами как запуска консольных утилит, так и использования пакетов/модулей, задача программиста (ну или админа/девопса, кто он там будет) - выбрать средства реализации и корректно их использовать. Очевидно, курл, сед и авк не являются уникальными с т.з. решаемых задач.
А на го, как и на абсолютно любом распространённом ЯП, не надо писать курл (а также сед, авк и прочие радости жизни), на них на всех сетевых клиентов - на любой вкус.
amkartashov
Вы предлагаете на каждый чих писать свою имплементацию той утилиты, которая вам в этот момент понадобилась? Вы обладаете настолько большим количеством ресурсов и времени, что вам без разницы, пролопатить man curl в поисках нужного ключа или прочитать документацию net/http и реализовать все edge cases самому? Ваши навыки убеждения помогут продвинуть ваши альтернативы курла и остальных утилит потребителям ваших "не-скриптов"?
siziyman
Повторяю: я не пишу утилиты, я решаю бизнес-задачи. Если для этого надо написать утилиту - бога ради, но в 99,999999% для этого можно использовать пару вызовов кода/утилит, написанных кем-то до меня. Иногда этот код даже под капотом те самые утилиты вызовет, но далеко не всегда, это просто неэффективно в большинстве случаев (что по ресурсам, что по поддержке этого кода в будущем).
Вы-таки не поверите, но бизнес-кода с HTTP-запросами на популярных ЯП написано совершенно невероятное количество, и как-то люди не умирают, не используя курл. Я, собственно, даже не упомню, когда при использовании распространенных HTTP-клиентов популярных ЯП, на которых я писал (притом это были по-моему 3 разных клиента на джаве и скале, и 1-2 на го), мне приходилось бы реально заморачиваться об эдж-кейсах - да, это были не скрипты, но это повышает требования к коду, а не понижает, потому что исполняется он не по ручному запросу в моём окружении.
Навыки моего убеждения не нужны: люди буквально каждый день пишут HTTP-запросы на любом ~высокоуровневом ЯП (на невысокоуровневых тоже, но предположим, что не каждый день). Курла там под капотом обычно нет.
amkartashov
я тогда не понимаю, с чем именно вы спорите. Я именно об этом и говорю.
sshikov
Ну таки вы говорите не об этом. Может вы это и имели в виду, но curl != модулю работы с http запросами. Модуль — это когда есть нормальное API, для того языка, на котором вы пишете. Когда модуль подключается одной строкой, как зависимость (чего в баше отродясь не было, поэтому в нем нельзя удобно использовать чужие модули, и нет репозитория модулей). А curl — это такой недомодуль, у которого только и есть что stdout и код возврата, по большому счету. API curl — это libcurl, или ее аналог для любого другого языка. И когда вам нужно http, это намного намного удобнее.
vvzvlad
Ну, правды ради, в куче ситуаций большего и не надо.
sshikov
Так никто не говорит, что
недомодулиутилиты нельзя применять. Можно конечно. Не надо делать из них приложения, из лучше сразу делать на libcurl, или что там у вас есть в языке.vvzvlad
Ну вот нет. Если я хочу просто скачать файл и положить его на диск, curl все-таки проще будет, чем libcurl или какая-нибудь http библиотека в питоне: сначала залезь в документацию, разберись как ее вызывать и настраивать, потом получи содержимое, обработай ошибки, потом разберись как писать на диск в файл, запиши, закрой приложение, верни правильный exit code.
Курл задачу скачивания файла делает одной командой с парой параметров. И зачастую ну вот ничего не надо больше, чем скачать этот файл.
sshikov
Скачать и положить — это все же не приложение. Против таких применений баша никто и возражать не будет.
siziyman
У вас какое-то максимально нечестное сравнение.
У курла тоже надо читать мануал, чтобы знать, что и как делать, тоже надо обработать ошибки. Закрыть приложение и вернуть дефолтный нулевой код - делается одной, а то и нулем строчек. Если вам надо настраивать стандартный хттп-клиент, то и курлу скорее всего тоже передать параметры надо будет
vvzvlad
Оно честное в рамках задачи «скачать файл».
Но впрочем, я нашел для питона wget, который делает тоже самое в две строки:
siziyman
Да не честное, потому что "а вот для курла нужна вот эта структура команды и вот эти параметры" вы почему-то взяли за заранее известное (а настройки клиента в ЯП - нет), да и про обработку ошибок в курсе умолчали, а для ЯП - сказали, что с ней надо разобраться. :)
vvzvlad
Ну мы же не в идеальном мире, где люди смотрят на абстрактную сложность освоения инструментов с нуля, а не оценивают ее суммарно с имеющимися навыками. Люди, которые пишут скрипты и прочитали эту статью, скорее всего уже знают, как пользоваться курлом до уровня «скачать файл». А как вызвать http-библиотеку в питоне я каждый раз гуглю или смотрю в коде, хотя делаю это не в первый раз.
Потому что курл либо скачивает файл, либо завершается с ненулевым кодом ошибки, механизмом, который унифицирован для других вызовов. Не получилось — попробуем еще раз, а после завершимся.
В питоне для этого надо писать дополнительную конструкцию, которая ловит исключения. Оно более гибкое, но более сложное.
unsignedchar
2 строки ;) (3 вместе с import)
Не так страшен тот питон, каким он кажется.
Документацию в любом случае нужно читать; man curl совершенно не маленький.
amkartashov
если у меня задача написать приложение, которое работает по http, то bash-скрипт с курлом у меня может появится максимум на этапе прототипирования. Если у меня задача автоматизировать ручные действия типа сборки или установки софта в предсказуемом окружении, то я не буду заморачиваться с изучением net/http или requests, а просто вызову wget/curl.
sshikov
Ну, я в общем с этим согласен. Я скорее вот о чем:
Речь не о том, чтобы писать свою реализацию curl/утилиты. Речь о том, что в других языках, не в баше, принято писать и использовать такое как модуль. libcurl, если угодно.
Потому что интеграция на уровне API нескольких разных модулей, кроме http, обычно получается гораздо проще.
Ну таки да. Вопрос в предсказуемости. Вот как только мне стало нужно проверить это самое окружение, так я сразу ухожу от bash и консольных утилит к API, если такой мне доступен. Как только мне нужно работать с чужим REST API, я обычно не буду это делать curl-ом, а таки возьму даже не http модуль, а что-то еще поудобнее. И мне кажется, автор все-таки примерно про это пишет — если вы пишете на баше, нужно себе четко представлять ограничения этого выбора. Они есть, и они хорошо известны.
Eugeeny
Вы удивитесь конечно, но 99.999% интернета не на libcurl работает
vvzvlad
Они что, все написали реализацию curl лучше авторов curl?! ©
Eugeeny
Это называется "HTTP" а не curl.сарказмодетектор сломался
amkartashov
Как-то не получилось у тебя мысль донести. curl это пример. 10 строк на баше, написанные за минуту могут заменить миллион строк на си, на которые потрачен человеко-век.
vvzvlad
Если что-то пишется на баше в одной строке и на это потрачен человеко-век, то скорее всего это вызов какого-то приложения. Если это вызов какого-то актуального приложения, то либо у этого приложения есть библиотека (как libcurl), к которой есть адаптер на распространенные языки, либо этот функционал так или иначе затащен во все языки готовыми либами.
Мне сложно представить что-то, что доступно только в виде бинарника, вызываемого в баше, но недоступно, скажем, в том же python.
Все эти grep/awk/sed/cut — доступны и вовсе без библиотек (а зачастую и не требуются, потому что можно получить выхлоп команд в json). curl/wget заменяются http. Пайплайны — вон выше plumbum предложили. Что еще такого незаменимого в баше обычно используется?
amkartashov
Я думал, это очевидно. Как оказалось нет.
Незаменимости никакой нет. Просто подумай, как долго ты будешь на go/python/etc писать аналог
, а главное, зачем? И как ты этот код на go/python будешь доставлять до места применения?
vvzvlad
Я бы ээ, попросил вас на вы обращаться, мы с вами на брудершафт не пили.
Этот код пишется в те же несколько строк (у меня ушло вот 6 минут, чтобы найти как это сделать в гугле):
Можно чуть короче, можно чуть длиннее. Можно не wget, а что-то более низкоуровневое. Зачем — зависит от того, что именно я делаю. Если вся задача — «установить docker-compose», то да, питон не нужен. Если задача чуть сложнее и включает в себя еще десяток команд — то питон внезапно оказывается более сопровождаемым и менее склонным к сюрпризам.
Так все-таки, эээ… что такого есть наработанного в баше, что нельзя заменить питоном?
amkartashov
np, если у вас аллергия на местоимения...
А вы его проверили? А вы подумали, как его запускать на целевой системе?
Нельзя баш заменить питоном там, где нет питона, но есть баш.
Можно ещё с этим поупражнятся https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 - там всего то надо заменить curl/gpg/sudo
vvzvlad
А, э, простите, я разве утверждал обратное?
Если питона нет, то на питоне писать не получится. Если в системе только sh, то не получится писать и на bash. Если в системе нет posix-вызовов, то там не получится запустить тот софт, который написан под linux. Если под систему нет stdlib, то там не получится запустить линукс вообще. Есть много ограничений на разных системах, с которыми приходится мириться.
Но в данном конкретном случае ваше возражение звучит как «а что ты будешь делать со своим питоном на системе где отсутствует питон, а? а? а?!». Ну ничего не буду делать. Как и вы с bash/sh на системах, где отсутствует то множество команд bash/sh, а есть только обрезанный busybox.
Но мы же не говорим про все системы в мире, мы обсуждаем возможную замену bash на python, допуская саму теоретическую возможность замены (т.е. подразумевая, что система нормальный arm/x86 с нормальным современным линуксом с возможностью ставить пакеты), чтобы обсуждение было предметным, а не скатывалось в попытки померяться ограниченностью систем оппонентов (—А у меня оперативки 4мб! —А у меня процессор без FPU!).
И вот в случае возможности запуска python как такового, уже можно обсуждать, а можно ли этот скрипт заменить на скрипт на питоне. Вы привели пример скрипта, я показал, что он переписывается на питоне, было бы желание. Думаю, не сильно погрешу против истины, если скажу, что и get-helm-3 тоже прекрасно переписывается на питоне. GPG — это python-gnupg, curl — Requests или wget и так далее. Заменить — можно.
А уж вопрос того, надо ли это — зависит от задач. Развесистый скрипт конфигурирования окружения в докере можно и заменить. Инсталлятор какого-то софта, который должен запускаться где угодно — может, и не стоит заменять.
edo1h
а он точно обрезанный? не натыкался на скрипты на posix shell, которые busybox не может запустить.
если же вы хотели сказать, что не стоит использовать башизмы без особой на то нужды, то не могу с вами не согласиться.
заменить-то можно, но доставка этого скрипта становится проблематичнее. нужно обеспечить наличие питона и кучки библиотек; curl же с gpg есть почти на каждой системе.
Eugeeny
Нечего и упражняться, скрипт - наполовину мусор, нужный чтобы все не развалилось из-за незаэскейпленных символов в именах, отсутствия curl (вот это неудобно вышло, да?)
И все это в виде дикого полотна в 120 символов шириной с пятикратным повторением одних и тех же имен
edo1h
реальный пример: понадобилось мне проверить обновился ли файл на сервере, если обновился — скачивать и запускать некоторое действие
в голанг же http.Get из net/http не умеет дополнительные хидеры. реализовать можно, но это будет не пара строчек, как на sh+curl
unsignedchar
r = request.urlopen(url)
if r.code == 200:
open (filename,"w).write(r.read())
Где-то так ;) Те же 3 строчки, но на Python. КМК, ничем не хуже по понятности кода.
ЗЫ: редактор на мобильном - днище.
edo1h
нет, не три строчки.
надо прочитать дату файла, засунуть её в if-modified-since в определённом формате.
и у меня речь шла про golang, а не про python, в golang у http.Get нет параметра headers. если идея обернуть мелкую утилитку на golang в шелловский скрипт ещё как-то укладывается в моей голове, то идея обернуть её же в питоновский скрипт мне не нравится.
unsignedchar
К сожалению, чтобы понять что именно делается в вызове curl, нужно помнить наизусть портянку man curl. Write only code во всей красе.
khajiit
А чтобы понять, что делается в коде произвольно взятой функции на произвольно взятом ЯВУ надо знать этот ЯВУ, используемый фреймворк, а зачастую еще и структуру и особенности тех штук, к которым есть обращения из этого кода. Write only code во всей красе, говорите? ;)
unsignedchar
Если я вижу обращение к методу headers() - я догадываюсь, что тут что-то связанное с заголовками в http. Если я вижу ключ -z .. ?
khajiit
… то он сопровождается
timecond
, и его значение становится предельно ясно из контекста так же, какhttp.headers()
?На самом деле, ваше утверждение:
эквивалентно:
чтобы понять что именно делается в вызове незнакомой функции нужно помнить наизусть портянку справки по всей библиотеке
.unsignedchar
Не буду сильно спорить.. обычно не нужно помнить все тонкости всех библиотек, чтобы увидеть, что вот здесь мы берём значение заголовка и с чем то сравниваем. А вот что такое Transfer based on a time condition ? В каком из форматов времени оно задаётся?
edo1h
слушайте, ну вы явно придираетесь, видно же, что в качестве параметра мы передаём имя локального файла
khajiit
Кстати, не только.
Вот что говорит справка:
Взять дату из файла, загрузить если удаленный файл новее:
curl -z local.html http://remote.server.com/remote.html
Взять дату из файла, загрузить если локальный файл новее:
curl -z -local.html http://remote.server.com/remote.html
Указать метку непосредственно:
curl -z "Jan 12 2012" http://remote.server.com/remote.html
edo1h
да, я в курсе, что есть несколько вариантов использования опции -z. имелось в виду, что в данном случае из контекста понятно какой вариант нужен (и да, именно он и используется)
khajiit
Да, простите, утерял контекст.
khajiit
Ну, можно было бы попробовать придраться к коротким ключам, но в выхлопе хелпа и длинный же видно. Да и на все опции коротких ключей не хватит.
А вот вопросами формата и типичного использования во время написания кода вам придется задаться и при подключении libcurl из языка, так что тут паритет.
В случае же заголовков все довольно прозрачно:
Но, опять же, изучать надо как выхлоп man или --help так и справку по libcurl. И, точно так же, часто используемые ключи/параметры запоминаются и в дальнейшем обращения к справке уже не требуют — вплоть до написания блоков кода по памяти, даже без использования подсказок IDE.
edo1h
хорошо, добавляем комментарий «download if remote version is newer than local». всё равно вариант с curl останется заметно компактнее.
зачем помнить наизусть? у вас man не работает?
unsignedchar
В 21 веке компактность исходников очень редко важна.
Одно дело писать код, поглядывая в документацию. Другое - когда без документации даже прочитать невозможно. Write only code - по возможности лучше этого избегать.
12rbah
amkartashov
где сейчас используются bash скрипты:
всякие ci/cd системы (circleci, github actions)
инит скрипты в контейнерах (entrypoint.sh, или даже сырой скрипт в манифестах k8s)
небольшие врапперы (от алиасов и функций в bashrc до небольших скриптов в $HOME/bin)
системы сборки (make)
configuration management (ansible)
системные скрипты для пихания в крон (бэкапы там) в системд
При этом очень часто код этих скриптов попадает в git.
Если заменить это на Go (замечательный язык, сам пользуюсь), то возникнут всякие сложности (всё решаемо, но всё-таки), например:
oneliner типа `curl url | jq .. || echo "can't"` превратится в портянку с main.go, +go.mod
в git придётся либо пихать бинарник, либо добавлять компилятор на стороне использования, кэшировать там зависимости и тд, следить за платформой
что-то по-быстрому поменять уже не получится
придёт сисадмин, который go не знает, ты его учить будешь? Либо будешь добавлять в вакансию требования знания go?
как ты код на go запихаешь в userdata AWS EC2 инстанса?
Про скорость уже написали.
Задачи типа обработки логов.. кто в своём уме будет писать это на баше?
khajiit
Кстати, вспоминается, кто-то на хабре писал, что zgrep'нуть пакованные json (и скормить jq, если надо) у них быстрее, чем писать запрос в эластик.
amkartashov
эм. ну да, можно. У меня почему-то в голове возникла картина, как кто-то на чистом баше без вызовов внешних утилит это делает... тупо конечно.
saterenko
Я обрабатываю логи в bash-е. Но логи у меня plain, а обрабатываются они типа grep 'ERROR'|grep '2022-03-29 10:00' с отправкой количества сообщений в graphite, на который настроена grafana с отображением всего этого и алертингом. Что-то типа:
jingvar
А как предлагаете на Го код править по месту?
Привезли бинари, программа фейлится и что делать?
на баше или питоне навтыкал принтов подебажил, поправил код и поехали
а контейнерами как? компилятор и исходники внутрь затаскивать?