хэшбанг Bash на macOS

Вопрос или проблема

На macOS #!/bin/bash означает, что скрипт будет использовать системный bash, который очень устарел (3.2, 2006 год) и (по крайней мере, для меня) в большинстве случаев бесполезен.

Затем вы можете установить современный bash, используя Homebrew или MacPorts, и использовать что-то вроде этого:

#!/usr/bin/env bash

Но подход с env ненадежен: что, если вы запустите этот скрипт на Mac, где установлен только системный bash? Тогда env будет использовать bash 3.2 (предполагаю…), и это приведет к неправильной работе скрипта, что может нанести вред.

Тогда третий подход

#!/opt/homebrew/bin/bash

Но что, если вы запустите этот скрипт на Mac, где современный bash установлен с помощью MacPorts вместо Homebrew?

Какова наилучшая практика в этом случае? (Может быть, создать символическую ссылку в /usr/local/bin, указывающую на /opt/homebrew/bin/bash, а затем использовать #!/usr/local/bin?)

#!/usr/bin/env bash — лучшая практика, env — лучшая практика для всех shebang. MacOS или нет, нет гарантии, что ваша целевая система будет иметь ту же версию bash, что и система, на которой вы пишете скрипт.

Если вы хотите добиться истинной портативности, вам нужно использовать #!/bin/sh, и даже тогда вам нужно знать, какие истинные POSIX-команды и методы доступны, потому что во многих системах /bin/sh просто является символической ссылкой на bash в режиме --posix и все равно позволит использовать не POSIX вещи, такие как массивы. Также у вас нет контроля над любыми внешними командами awk, sed, grep и другими, которые используются и будут различаться от системы к системе.

На macOS после свежей установки homebrew переменная $PATH выглядит так

% echo $PATH
/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:...

% which -a bash
/opt/homebrew/bin/bash
/bin/bash

Так как homebrew размещает свою bin директорию перед /bin в $PATH, и shell просматривает эту переменную с начала до конца при поиске исполняемых файлов, он будет запускать bash 5 без проблем с #!/usr/bin/env bash.

Ответ или решение

На macOS использование shebang-системы и особенно выбора между различными версиями Bash — это зачастую нелегкая задача для разработчиков и системных администраторов. Исторически сложилось, что в macOS предустановлена устаревшая версия Bash 3.2, датированная 2006 годом. Это связано с лицензионными ограничениями GPL, из-за которых Apple прекратила обновлять Bash на своих системах. Однако современные требования и сценарии использования требуют более новых функций, доступных в последних версиях Bash.

Теория

Shebang — это строка, начинающаяся с #!, расположенная в начале скрипта, которая указывает системе, какой интерпретатор использовать для выполнения данного скрипта. В контексте macOS, три основных подхода к использованию shebang включают:

  1. Прямое указание на системный Bash: #!/bin/bash. Это приведет к использованию Bash 3.2, что не всегда приемлемо.

  2. Использование env для динамического поиска Bash: #!/usr/bin/env bash. Это подход, который позволяет системе найти bash в соответствии с переменной окружения PATH. Обычно он применяется для увеличения кроссплатформенности скриптов.

  3. Указание полного пути к современному Bash: #!/opt/homebrew/bin/bash или путь от MacPorts, в зависимости от того, как установлен современный Bash. Этот подход может вызывать проблемы, если скрипт выполняется на системе, где Bash установлен по другому пути.

Пример

Рассмотрите следующий сценарий: вы разрабатываете скрипт на macOS, используя новые возможности Bash, недоступные в версии 3.2. Установив более новую версию Bash через Homebrew (brew install bash), она будет находиться в /opt/homebrew/bin, и ваш $PATH будет настроен так, чтобы сначала искать исполняемые файлы в /opt/homebrew/bin. Таким образом, использование #!/usr/bin/env bash будет достаточно для того, чтобы скрипт применял установленную через Homebrew версию Bash.

#!/usr/bin/env bash
echo "Hello from a modern Bash!"

Приложение

1. Использование env для поиска интерпретатора

Использование #!/usr/bin/env bash — самый распространенный и рекомендуемый метод из-за его гибкости и универсальности. При условии, что Homebrew установлен и его путь включен в переменную окружения PATH, этот подход автоматически выберет версию Bash, установленную из Homebrew или MacPorts, обеспечивая тем самым выполнение скрипта в более современной среде без необходимости постоянного обновления путей.

Такой метод не лишен недостатков. Если Homebrew-версия Bash недоступна, env все же выберет устаревший системный Bash. Чтобы смягчить эти риски, рекомендуется четко документировать зависимость скрипта от определенных функций Bash и предлагать инструкцию по установке Homebrew и настройки системы пользователям или клиентам.

2. Создание символических ссылок

Альтернативное решение — создание символических ссылок. Вы можете создать ссылку на современный Bash в /usr/local/bin, что устранит необходимость изменения shebang в случае изменения способа установки Bash.

ln -s /opt/homebrew/bin/bash /usr/local/bin/bash

Символическая ссылка обеспечит независимость скрипта от специфик местоположения файлов в системе, но все же потребует базового администрирования и может потребовать прав суперпользователя.

3. Исполнение в POSIX-совместимом режиме

И, наконец, если ваш скрипт не критичен к возможностям Bash, рассмотрите использование /bin/sh для обеспечения максимальной совместимости. Однако этот метод предполагает знание POSIX-совместимых возможностей и ограничений.

Заключение

В профессиональной среде важно, чтобы написанные вами скрипты были как можно более переносимы и адаптируемы под особенности различных систем. Хотя #!/usr/bin/env bash не лишено недостатков, это все же наилучший выбор для большинства пользователей, стремящихся к сочетаемости между различными операционными системами и окружениями. Это же правило распространяется на создание образов Docker, в которых вы можете контролировать интерпретатор и его версию, еще больше упрощая разработку.

Применяя подобные подходы, вы сможете значительно упростить управление зависимостями ваших проектов и уверенно интегрировать их в разнообразные операционные среды. Обратите внимание на тщательное документирование используемых версий и требований к среде выполнения для облегчения процесса развертывания и сопровождения вашим возможным будущим коллегам или пользователям.

Оцените материал
Добавить комментарий

Капча загружается...