Вопрос или проблема
Очевидно, что когда вы запускаете Bash-скрипт с помощью sh
(например, sh ./path/to/bash-script.sh
), вы можете столкнуться с ошибками в случаях, когда sh является символической ссылкой на не-Bash оболочку, которая не поддерживает функцию, используемую в скрипте.
Мне любопытно, может ли быть случай, когда скрипт, предназначенный для Bash, выполняемый с помощью dash или какой-либо базовой POSIX оболочки, приведет к выполнению кода, который в противном случае определенно не был бы выполнен.
Все, что я тестировал (например, группировка команд (( ... ))
), просто заставляет скрипт завершаться преждевременно при выполнении с помощью примитивной POSIX оболочки, не вызывая никакого потенциального ущерба.
У меня нет ответа, который вы ищете, и я уверен, что кто-то может предложить несколько действительно интересных примеров, но ответ на ваш вопрос однозначно “да”.
Как вы упоминаете, запуск bash-скрипта с помощью posix оболочки, вероятно, приведет к нескольким ошибкам, которые заставят код выполняться всевозможными неожиданными способами, и это может быть очень опасно. Существует практически бесконечное количество способов, как выполнение else
из-за неожиданной ошибки, когда вы должны были выполнить if
, может считаться “опасным” для производственной инфраструктуры.
Простой пример:
$ cat shtest.sh
#!/usr/bin/env bash
if [[ a == a ]]; then
echo bash
else
echo dash
fi
$ ./shtest.sh
bash
$ dash ./shtest.sh
./shtest.sh: 3: [[: not found
dash
Конечно, вы получите ошибку, но код в части else все равно выполнится. А что если это будет:
if [[ $server == in_use ]]; then
do_thing
else
delete_server
fi
Я думаю, что что-то, что вы ищете, это команды, которые не вызывают ошибок, например, расширение фигурных скобок.
Например, если у вас есть скрипт, который проверяет состояние lb_{1..3}
, вы можете сказать, что если один из них не работает, запустите другой lb-сервер. При выполнении с помощью dash он интерпретирует lb_{1..3}
как буквальную строку вместо lb_1
, lb_2
, lb_3
и потенциально создаст сотни ненужных замен.
Все, что я тестировал (например, группировка команд
(( ... )))
), просто заставляет скрипт завершаться преждевременно…
Синтаксис ((...))
предназначен для арифметических выражений, а не для группировки команд.
Я не думаю, что такие ошибки обязательно заставят скрипт завершиться преждевременно. Это зависит от того, считается ли выражение синтаксической ошибкой (что приведет к завершению оболочки) или просто интерпретируется как недопустимая команда. Рассмотрим что-то вроде этого:
MYVAR=3
if (( MYVAR > 2 )); then
echo "Выполнить действие 1"
else
echo "Выполнить действие 2"
fi
Если я запущу этот скрипт с помощью bash
, мы увидим:
$ bash example.sh
Выполнить действие 1
Но если я запущу скрипт с использованием не-Bash оболочки, такой как dash
, мы увидим:
$ dash example.sh
example.sh: 3: MYVAR: не найден
Выполнить действие 2
Наша попытка использовать функцию, специфичную для bash, терпит неудачу, но не вызывает выхода оболочки; она просто продолжает и выполняет действие, отличное от ожидаемого (в данном случае это потому, что dash рассматривает ((...))
как оператор вложенной подсистемы, поэтому он пытается выполнить MYVAR
как команду). Кроме того, выражение MYVAR > 2
будет интерпретироваться как перенаправление ввода-вывода оболочки, так что оно создаст или перезапишет файл с именем 2
.
Это “опасно”? Не уверен, но это определенно может привести к неожиданному поведению.
Второй пример: рассмотрите вот такой скрипт:
shopt -s nullglob
for x in *foo; do
echo "$x"
done
Команда shopt
специфична для bash. Запуск этого в bash (предположим, что у вас нет файлов, соответствующих шаблону в вашей текущей директории) не приведет к выводу.
Запуск этого с помощью dash
приведет к:
example.sh: 1: shopt: не найден
*foo
Если вы использовали результат этого выражения для создания файлов, это могло бы привести к тому, что dash
создаст недопустимые файлы и снова может вызвать неожиданное поведение в скрипте.
Ответ или решение
Запуск Bash-скрипта с использованием sh
действительно может представлять собой потенциальную опасность, особенно если sh
ссылается на оболочку, не поддерживающую все конструкции и возможности, доступные в Bash. Это может привести к неожиданному поведению скриптов, что может вызвать множество проблем, включая утечку данных, потерю информации и даже возможность взлома системы.
Проблемы совместимости
Когда вы запускаете скрипт, созданный для Bash, через другую оболочку, например, dash
, некоторые команды могут не выполняться из-за отсутствия поддержки соответствующих синтаксических конструкций. Простые элементы, такие как условные конструкции if
, могут привести к разному поведению, если они используют синтаксис, присущий только Bash. Например, использование двойных квадратных скобок [[...]]
для проверки условий не будет поддерживаться в dash
, что приведёт к ошибкам.
#!/usr/bin/env bash
if [[ a == a ]]; then
echo "bash"
else
echo "dash"
fi
Запуск этого кода с dash
приведёт к ошибке:
./shtest.sh: 3: [[: not found
Однако, скрипт всё равно продолжит выполнение, что откроет путь для потенциально небезопасного выполнения кода в блоке else
.
Непредсказуемое поведение
При использовании оболочки, которая не поддерживает все функции Bash, ошибки могут приводить к выполнению нежелательного кода. Например:
if [[ $server == in_use ]]; then
do_thing
else
delete_server
fi
Если условие [[...]]
не будет распознано, и скрипт перейдёт к выполнению блока else
, это может иметь серьезные последствия, если delete_server
выполняет разрушительные действия.
Условные выражения и перенаправление
Ваша логика может также ошибочно выполниться, если вместо ожидаемого поведения будет интерпретировано неверное. Например, конструкция ((...))
, предназначенная для арифметики в Bash, может быть распознана dash
как команда, что также приведет к неожиданным результатам:
MYVAR=3
if (( MYVAR > 2 )); then
echo "Do thing 1"
else
echo "Do thing 2"
fi
В dash
эта конструкция вызовет ошибку, но затем скрипт продолжит выполнение, что может привести к попытке выполнения неправильной логики с неожиданным результатом.
Глобальные параметры и шапка shopt
Еще один пример, который стоит рассмотреть, это использование команды shopt -s nullglob
:
shopt -s nullglob
for x in *foo; do
echo "$x"
done
Эта команда не распознается в dash
, и вместо того, чтобы ничего не выводить (что правильно для Bash), она напечатает *foo
, что может создать ошибки в следующем коде, если он зависит от переменной x
.
Заключение
Запуск скриптов Bash с использованием sh
может привести к опасным багам и подрыву безопасности системы из-за выполнения неожиданного кода. Рекомендуется всегда использовать оболочку, соответствующую синтаксису и возможностям скрипта, чтобы избежать ошибок, которые могут быть неочевидными на первый взгляд. Всегда тестируйте ваши скрипты в целевой среде, чтобы гарантировать, что они работают как задумано, и избегайте взаимодействия с чувствительными данными в тестовее.