«Бить (Bash) или не бить», - спрашивал один датский принц. Вот и у меня возник аналогичный вопрос, когда у нас в компании появился сервер сборки Bamboo. Как можно в задании Bamboo, выполняющем скрипт Bash или Cmd, написать команды, одновременно понятные интерпретатору командной строки Windows и оболочки Linux?
У нас в компании в качестве скриптового языка планов Bamboo используется кроссплатформенный язык Python. Но для запуска скриптов в Windows и Linux используется разный код, примерно следующего содержания:
Windows:
call %PYTHON_ENV%\Scripts\activate.bat
python имя_скрипта.py %bamboo_issue_key%
Linux:
source ~/.bash_profile
source $PYTHON_ENV/bin/activate
python имя_скрипта.py $bamboo_issue_key
Команды, понятные Linux, будут обработаны с ошибкой в Windows и наоборот. Что делать в этой ситуации? Запускать задания только для агентов с определенной операционной системой - отвергая половину доступных агентов? Я распечатал для сравнения список всех команд Bash и Windows command; пытался найти ответ в интернете; задавал вопросы на профильных сайтах. Наконец на stackoverflow я нашел изящное решение.
В Windows Cmd, строка, начатая с символа «:», обозначает начало метки. Если имя метки отсутствует или не содержит корректное название с точки зрения командного процессора, то эта строчка игнорируется! А что в Linux? Символ двоеточие «:» эквивалентен true в большинстве POSIX-оболочек. Исторически сложилось так, что в Bash нет встроенных команд true и false. Вместо этого true был просто псевдонимом «:», а false — чем-то вроде let 0.
В Linux нет команды goto. Но с помощью синтаксиса heredocs, можно обеспечить пропуск одного или несколько разделов кода:
echo "Run this"
cat >/dev/null <<GOTO_1
echo "Don't run this"
GOTO_1
echo "Also run this"
Сложив все знания, указанные выше, мы получаем следующий код:
:<<"::CMDLITERAL"
@ECHO OFF
GOTO :CMDSCRIPT
::CMDLITERAL
source ~/.bash_profile
source $PYTHON_ENV/bin/activate
python -c "import platform; print(f\"{platform.system()}\")"
exit $?
:CMDSCRIPT
call %PYTHON_ENV%\Scripts\activate.bat
python -c "import platform; print(f\"{platform.system()}\")"
Красивое решение, позволяющее выполнять план Bamboo на любом агенте (Linux или Windows) с установленным интерпретатором Python.
Единственное что я не объяснил – что за странные символы $? идущие после команды exit.
В Bash символы $? должны стоять перед следующей строчкой с двоеточием «:», потому что «:» сбрасывается $? в 0 (false).
В обсуждении на stackoverflow были предложены и другие решения, но мне показалось, что изложенное в статье решение более лаконично и визуально разделяет код Bash и Cmd.
Не верьте, когда вам говорят, что это сделать невозможно. Чуть больше усилий - и в результате Вы можете запускать кроссплатформенные скрипты, выполняющиеся как в Linux, так и в Windows.