Как стать автором
Обновить

Комментарии 39

Спасибо за перевод,


Придётся закавычивать каждый аргумент и экранировать любые символы, необходимые для выхода из этих кавычек…
Как использовать этот трюк для безопасного выполнения команд по ssh? Это невозможно!

Как вариант можно использовать base64 и передавать уже закодированную строку для выполнения. А на другом конце просто делать:


echo "$CMD" | base64 -d | bash

В случае с bash можно также обойтись простой передачей необходимого через пайп.


Еще хотелось бы добавить про экранирование Here Document, например все знают, что эта команда:


CITY=Moscow
cat <<EOT
I live in $CITY
EOT

вернет:


I live in Moscow

Это может быть удобно для подстановки переменных в Here Document.
При необходимости знак "$" и скобки можно экранировать с помощью "\"


Но мало кто знает, что можно заэкранировать весь Here Document целиком, например:


BBB=asd
cat <<\EOT
I live in $CITY
EOT

не станет расскрывать переменные и вернет:


I live in $CITY

Это может быть полезным для выполнения скриптов на удаленной машине, например.

Еще один способ выстрелить в ногу из баша. Весь Here Document экранируется одним слешом — не знал. Глаз может и не заметить.

Тогда уж лучше так (закавыченный маркер):


cat <<'EOT'
$HOSTNAME
EOT
`` я чаще всего испольхую вместе с for, а там лишние "" мешают. Безопасного варианта этой конструкции я так и не придумал.
Если приходится писать много bash-скриптов (или один, но длинный), то что-то пошло не так. И скорее всего, выбран неправильный инструмент (или переизобретение существующего).
Есть большое количество automation tools, которые помогут минимизировать количество bash.

Для bash есть какие-нибудь дебаггеры?

Угу. strace.

bashdb.sourceforge.net
Есть приложения, целиком написанные на bash. Например, обёртка на пакетным менеджером Arch Linux yaourt. Читать такой код довольно сложно.
Был ещё freenx — тоже то ещё поделие на bash, ужасающий и громоздкий код.
Считаю что bash хорошо подходит именно для сценариев управления *nix сервера. Он напрямую работает с системными утилитами и не перенасыщен синтаксическими конструкциями (сахаром) — потому является отличным связующим субстратом для создания системных скриптов с относительно низким порогом вхождения.
Как язык для написания больших программ и утилит bash просто ужасен:
Неудобное и не очевидное управление переменными и их типами;
Отсутствие понятие зон видимости переменных — в результате в большом скрипте сложно их отслеживать;
Сложно парсить вывод утилит и файлов — приходится применять всякие сторонние awk и sed, с тем ещё синтаксисом;
Отсутствие возможности работы с каким либо сторонним API, bash биндингов ожидаемо не существует;
Ну и банально — катастрофически медленное выполнение циклов и условий — по сравнением с bash даже python кажется спринтером.
п.с:
Потому считаю что bash очень хорош, но в своей нише использования. Остальное от лукавого :)

Bash это классный и выразительный язык, если уметь на нем писать. Там есть локальные переменные, функции и много всего остального. В качестве примера рекомендую исходники git или подсистемы конфигурации в openwrt.

НЛО прилетело и опубликовало эту надпись здесь
Все это есть и в других языках. А дебагера вот в баше нет.
НЛО прилетело и опубликовало эту надпись здесь
Поверьте — я прекрасно знаю как писать на bash, в том числе большие утилиты: тыц и тыц. И когда это разумно — то использую его по максимуму. Разговор о том что не нужно заниматься «ненормальным программированием тетриса на матлабе» — по назначению нужно вещь использовать.
Или, например, winetricks.
О безопасном программировании на bash есть хорошая страница в wiki mywiki.wooledge.org/BashPitfalls

Половина git написана на bash.

Очень большая статья, можно сократить:

Как безопасно программировать в bash.

Программируйте в нормальных языках программирования, а шелл оставьте для ad-hoc однострочников
> Как безопасно программировать в bash.

Никак.
НЛО прилетело и опубликовало эту надпись здесь
От сквозняков и добрых людей, очевидно же :)
НЛО прилетело и опубликовало эту надпись здесь

Тут скорее пытаются рассмотреть инфузорию-туфельку молотком.

Большие баш скрипты, в которых есть ветвления и нелинейная логика более 5 строк я бы жёг напалмом.

У bash до смешного низкий порог входа. Но дальше все как у взрослых. В языке есть куча средств для работы со сложностью, но осилить man bash, а главное понять, хватает не всех.

В природе уже есть версия баша, которая скушает следующее?
"$var1"«more string content»"$var2"

И куда катится мир? :)

На кой чорт человечество выдумывает такое количество символов кавычек?

Ждём продолжения, отвечающего на вопрос «зачем».
но что хорошего в совместимости

Совместимость это очень хорошо, но не всегда это нужно.
Незакавыченная переменная должна расцениваться как взведённая бомба: она взрывается при контакте с пробелом. Да, «взрывается» в смысле разделения строки на массив.
Видите ли, такое поведение достаточно часто требуется. Например:
arguments="xvzf archive.tgz -C /home/user"
tar $arguments
С кавычками это будет работать неправильно, т.к. команда должна получить командную строку, порезанную на аргументы функции main().
arcfile="archive.tgz"
current_dir="/home/user"
tar xzvf "$arcfile" "$current_dir"


Скажем так, ваш случай выглядит не так чтобы вынужденно-обязательным. При этом, если часто надо такое писать — можно и функции завести с нужным шаблоном аргументов…
Что-то я слабо представляю, как это сделать в случае, когда количество параметров м.б. произвольным.

Рекомендую глянуть в файл /etc/rc.conf во FreeBSD — там параметры работы системы задаются в виде аргументов командной строки (ну и есть параметры, указывающие, нужно ли вообще запускать эту команду — например, команду запуска демона, аргументы к которой заданы во второй переменной).

Вот только если имя пользователя или архива содержит пробел — такой способ уже не сработает.


Вот такой способ выглядит более общим:


arguments=(xvzf "архив с пробелом.tgz" -C /home/user)
tar ${arguments[*]}
for i in ${!arguments[@]};do w=$w\ \"${arguments[${i}]}\";done; tar $w

ЗЫ.
«Товарищи грузины, учитесь военному делу настоящим образом. Приедем — проверим!»

Однажды мне понадобилось выполнить некий набор команд на удаленной машине. Чтобы не мучиться с кавычками сделал так:


some-function() {
    : # do something useful
}

{
    declare -f some-function
    echo "some-function some-parameters"
} | ssh some-host bash
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.