Комментарии 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 экранируется одним слешом — не знал. Глаз может и не заметить.
`` я чаще всего испольхую вместе с for, а там лишние "" мешают. Безопасного варианта этой конструкции я так и не придумал.
Если приходится писать много bash-скриптов (или один, но длинный), то что-то пошло не так. И скорее всего, выбран неправильный инструмент (или переизобретение существующего).
Есть большое количество automation tools, которые помогут минимизировать количество bash.

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

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

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

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

Программируйте в нормальных языках программирования, а шелл оставьте для ad-hoc однострочников
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Большие баш скрипты, в которых есть ветвления и нелинейная логика более 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
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.