«Бить (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)


  1. Shaz
    31.01.2022 09:46
    +1

    Решение конечно интересное,даже красивое.

    Но вот вопрос, а нельзя это было решить силами самого bamboo? И запускать скрипт соответствующий ОС агента? Спрашиваю потому что с bamboo дел не имел.


    1. alisichkin Автор
      31.01.2022 10:45

      В 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.


      1. mayorovp
        31.01.2022 11:47
        +1

        А почему бы не добавить две разные задачи, ограничив их запуск через механизм условий (condition)?


        1. alisichkin Автор
          31.01.2022 12:13

          Да, возможно Вы правы, но ..
          Механизм условий для задач (Task в терминах Bamboo) работает только с переменными.
          Т.е. на уровне агента нужно создать переменную типа bamboo_is_win и bamboo_is_linux. А я не имею доступа к администрированию сервера Bamboo и его агентов.


  1. Elsedar
    31.01.2022 12:28
    +1

    А powershell не смотрели? Он ведь кросс-платформенный.


    1. alisichkin Автор
      31.01.2022 12:36

      Изначально разработка велась на PowerShell - но руководству он пришелся не по душе и было принято решение все переписать на Python.
      Я проработал механизм Модулей (библиотек в PowerShell) что позволяло повторно использовать код и ускорить разработку. Но, к сожалению, эта работа не оказалось необходимой в компании.


      1. vzhicharra
        31.01.2022 16:15
        +2

        э...

        т.е. из-за самодурства начальства рабочий кросс-платформ заменили на адовые костыли с увеличенной вдвлое вероятностью ошибки?...

        БЕГN!!!


    1. BrennendeHerz
      01.02.2022 01:49

      bash тоже кросплатформенный, в том смысле, что есть пакеты и для 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?


  1. 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г) выкладывал, тут что-то так руки и не дошли. А оказывается, я не один такой извращенец :)


    1. Nnnnoooo
      01.02.2022 21:01

      зачетненько :))))


      Ради таких комментов все еще стоит читать хабр :)


    1. alisichkin Автор
      01.02.2022 22:28

      Так я и не говорил, что придумал. Решение взято с stackoverflow. Обидно другое, что решение не заинтересовало читателей habr'a. Технические статьи здесь больше не интересны. В 15 году это бы зашло :(


      1. AVX
        01.02.2022 22:34

        Тогда и к статьям как-то более требовательно относились. А я не писатель, тяжело даётся. Просто код с комментариями выложить правила запрещают.


  1. alisichkin Автор
    01.02.2022 22:41

    Я тоже не писатель. Вторая статья с 14 года. А единый скрипт bash/cmd/ps это красивое решение.