«Бить (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.
Комментарии (13)
Elsedar
31.01.2022 12:28+1А powershell не смотрели? Он ведь кросс-платформенный.
alisichkin Автор
31.01.2022 12:36Изначально разработка велась на PowerShell - но руководству он пришелся не по душе и было принято решение все переписать на Python.
Я проработал механизм Модулей (библиотек в PowerShell) что позволяло повторно использовать код и ускорить разработку. Но, к сожалению, эта работа не оказалось необходимой в компании.vzhicharra
31.01.2022 16:15+2э...
т.е. из-за самодурства начальства рабочий кросс-платформ заменили на адовые костыли с увеличенной вдвлое вероятностью ошибки?...
БЕГN!!!
BrennendeHerz
01.02.2022 01:49bash тоже кросплатформенный, в том смысле, что есть пакеты и для Windows, а установка не сложнее чем PowerShell на Linux.
Простейший способ установить - поставить пакет "Git for Windows" не отказываясь от установки вспомогательных утилит. Есть и другие способы. После чего bash, grep, awk и less начинают помогать жить и в Windows.
Теоретически после подобной установки из Bamboo можно выполнять команду bash -c "python ...." в обеих ОС. Если конечно установка git допустима на нодах с Windows. Хотя если уж установка PowerSell была допустима на узлах с Linux, то ответ о возможности установки bash на нодах с Windows скорее "да".
Удивляет то, что в Bamboo до сих пор не реализовано создание собственных методов. Неужели только вызов команд оболочки? Нельзя написать метод-оболочку для исполнения команды в зависимости от операционной системы?
Вопрос тогда скорее не о причинах выбора Python вместо PowerShell, а в причинах выбора Bamboo. Интеграция с Jira?
AVX
01.02.2022 20:35Эй! не воруйте мои идеи! Это я уже неоднократно указывал и тут где-то тоже.
Код датирован ноябрём 2015 года.
Вот кусочек:
#!/bin/bash echo ^ echo ' GOTO WIN ' echo ^ echo ` echo<<comment <# --------------------------------------------------------------- .cmd ---- comment` # весь текст далее, начинающийся с решётки, интерпретируется bash и powershell # как комментарий. В местах, где выполняется код под win cmd (bat), решётки не # будут восприниматься как комментарии! Это строки 1-10 и далее с метки WIN и # до начала кода для powershell.
Файл сохранял как .bat, в линуксе надо дополнительно флаг исполняемого поставить. В итоге там три языка - cmd, bash, powershell. Скрипт сам себя передаёт в powershell в качестве кода powershell в виндах. И просто исполняется в bash под линуксом.
P.S. когда-то хотел статью такую написать, типа "ненормальное программирование". На ресурсе Intel IT Galaxy (закрыт с 2016г) выкладывал, тут что-то так руки и не дошли. А оказывается, я не один такой извращенец :)
alisichkin Автор
01.02.2022 22:28Так я и не говорил, что придумал. Решение взято с stackoverflow. Обидно другое, что решение не заинтересовало читателей habr'a. Технические статьи здесь больше не интересны. В 15 году это бы зашло :(
AVX
01.02.2022 22:34Тогда и к статьям как-то более требовательно относились. А я не писатель, тяжело даётся. Просто код с комментариями выложить правила запрещают.
alisichkin Автор
01.02.2022 22:41Я тоже не писатель. Вторая статья с 14 года. А единый скрипт bash/cmd/ps это красивое решение.
Shaz
Решение конечно интересное,даже красивое.
Но вот вопрос, а нельзя это было решить силами самого bamboo? И запускать скрипт соответствующий ОС агента? Спрашиваю потому что с bamboo дел не имел.
alisichkin Автор
В Bamboo планы состоят из Stages внутри которых содержатся Job'ы (различных видов), которые и выполняют работу.
Для запуска Python скриптов, создается Script Job. В документации сказано: "Script task is flexible enough to allow the possibility to use: the default shells on Linux (/bin/sh) or Windows (cmd.exe)"
Поскольку перед запуском Python необходимо настроить виртуальное окружение для корректной работы, то требуется выполнить activate.bat в Windows и activate в Linux. Плюс требуется передать скрипту параметры Bamboo, который в Windows ограничивается символами %% а в Linux начинается с $. Абсолютно разный синтаксис.
Так что мне не удалось решить это силами самого Bamboo.
mayorovp
А почему бы не добавить две разные задачи, ограничив их запуск через механизм условий (condition)?
alisichkin Автор
Да, возможно Вы правы, но ..
Механизм условий для задач (Task в терминах Bamboo) работает только с переменными.
Т.е. на уровне агента нужно создать переменную типа bamboo_is_win и bamboo_is_linux. А я не имею доступа к администрированию сервера Bamboo и его агентов.