Почему #!/Usr/bin/env bash превосходит #!/Bin/bash?
Я видел в нескольких местах, включая рекомендации на этом сайте (Что является предпочтительным Bash shebang?), чтобы использовать #!/usr/bin/env bash
в предпочтение #!/bin/bash
. Я даже видел, как один предприимчивый человек предлагал использовать #!/bin/bash
не так, и Bash функциональность будет потеряна при этом.
Все, что сказано, я использую Bash в жестко контролируемой тестовой среде, где каждый диск в обращении по существу является клоном одного ведущего диска. Я понимаю аргумент переносимости, хотя это не обязательно применимо в моем случае. Есть ли другая причина, чтобы предпочесть #!/usr/bin/env bash
по сравнению с альтернативами и, предполагая, что переносимость вызывает беспокойство, есть ли какая-либо причина, по которой это может нарушить функциональность?
Ответы
Ответ 1
#!/usr/bin/env
выполняет поиск PATH
для bash
, а bash
не всегда находится в /bin
, особенно в системах, отличных от Linux. Например, в моей системе OpenBSD она находится в /usr/local/bin
, так как она была установлена как дополнительный пакет.
Если вы абсолютно уверены, что bash
находится в /bin
и всегда будет, нет никакого вреда в том, чтобы поместить его прямо в ваш shebang, но я бы рекомендовал против него, потому что все сценарии и программы имеют жизнь за пределами того, что мы изначально что они будут иметь.
Ответ 2
Стандартное расположение bash равно /bin
, и я подозреваю, что это верно для всех систем. Однако, что, если вам не нравится эта версия bash? Например, я хочу использовать bash 4.2, но bash на моем Mac находится в 3.2.5.
Я мог бы попробовать переустановить bash в /bin
, но это может быть плохая идея. Если я обновляю свою ОС, она будет перезаписана.
Однако я мог установить bash в /usr/local/bin/bash
и настроить мой PATH на:
PATH="/usr/local/bin:/bin:/usr/bin:$HOME/bin"
Теперь, если я укажу bash
, я не получу старую грубую в /bin/bash
, но более новую, более сильную в /usr/local/bin
. Ницца!
Кроме сценариев оболочки, это !# /bin/bash
shebang. Таким образом, когда я запускаю свои сценарии оболочки, я получаю эту старую и паршивую версию bash, которая даже не имеет ассоциативных массивов.
Использование /usr/bin/env bash
будет использовать версию bash, найденную в моем PATH. Если я настрою свой PATH, чтобы выполнялся /usr/local/bin/bash
, то bash, который будут использовать мои скрипты.
Редко видеть это с помощью bash, но он намного чаще встречается с Perl и Python:
- Некоторые выпуски Unix/Linux, которые сосредоточены на стабильности, иногда отстают с выпуском этих двух языков сценариев. Недавно RHEL Perl был на 5.8.8 - восьмилетней версии Perl! Если кто-то хотел использовать более современные функции, вам пришлось установить свою собственную версию.
- Программы, такие как Perlbrew и Pythonbrew, позволяют устанавливать несколько версий этих языков. Они зависят от сценариев, которые управляют вашим PATH, чтобы получить нужную вам версию. Жесткое кодирование пути означает, что я не могу запустить my script под brew.
- Это было не так давно (хорошо, давно), что Perl и Python не были стандартными пакетами, включенными в большинство Unix-систем. Это означало, что вы не знали, где были установлены эти две программы. Было ли это под
/bin
? /usr/bin
? /opt/bin
? Кто знает? Использование #! /usr/bin/env perl
означало, что мне не нужно было знать.
И теперь почему вы не должны использовать #! /usr/bin/env bash
Когда путь жестко закодирован в shebang, я должен работать с этим интерпретатором. Таким образом, #! /bin/bash
заставляет меня использовать установленную по умолчанию версию bash. Поскольку функции bash очень стабильны (попробуйте запустить версию 2.x в Python script под Python 3.x), очень маловероятно, что мой конкретный bash script не будет работать, и поскольку мой bash script, вероятно, используется этой системой, а другие системы, используя нестандартную версию bash, могут иметь нежелательные эффекты. Очень вероятно, что я хочу убедиться, что стандартная версия bash используется с моей оболочкой script. Таким образом, я, вероятно, хочу жестко закодировать путь в моем shebang.
Ответ 3
Для вызова bash
это немного перебор. Если у вас нет нескольких двоичных файлов bash
, таких как ваш собственный в ~/bin, но это также означает, что ваш код зависит от того, имеет ли PATH правильные вещи.
Это удобно для таких вещей, как python
. Существуют сценарии оболочки и среды, которые приводят к использованию альтернативных исполняемых файлов python
.
Но ничто не теряется, если использовать точный путь к двоичному файлу, если вы уверены, что это тот, который вы действительно хотите.
Ответ 4
Существует множество систем, которые не имеют Bash в /bin
, FreeBSD и OpenBSD, чтобы назвать несколько. Если ваш script предназначен для переносимости для многих разных Unices, вы можете использовать #!/usr/bin/env bash
вместо #!/bin/bash
.
Обратите внимание, что это не выполняется для sh
; для сценариев, совместимых с Bourne, я использую только #!/bin/sh
, так как я думаю, что почти каждый существующий Unix имеет sh
в /bin
.
Ответ 5
#!/usr/bin/env bash
определенно лучше, потому что находит путь к исполняемому файлу bash из переменной системной среды.
Перейдите в свою оболочку Linux и введите
env
Он напечатает все переменные среды.
Перейдите к сценарию оболочки и введите
echo $bash.
Он напечатает ваш путь bash (в соответствии со списком переменных среды), который вы должны использовать для построения правильного пути shebang в вашем скрипте.
Ответ 6
Я бы предпочел обернуть основную программу в скрипт, как показано ниже, чтобы проверить все bash
, доступные в системе. Лучше иметь больше контроля над версией, которую он использует.
#! /usr/bin/env bash
# This script just chooses the appropriate bash
# installed in system and executes testcode.main
readonly DESIRED_VERSION="5"
declare all_bash_installed_on_this_system
declare bash
if [ "${BASH_VERSINFO}" -ne "${DESIRED_VERSION}" ]
then
found=0
all_bash_installed_on_this_system="$(\
awk -F'/' '$NF == "bash"{print}' "/etc/shells"\
)"
for bash in $all_bash_installed_on_this_system
do
versinfo="$( $bash -c 'echo ${BASH_VERSINFO}' )"
[ "${versinfo}" -eq "${DESIRED_VERSION}" ] && { found=1 ; break;}
done
if [ "${found}" -ne 1 ]
then
echo "${DESIRED_VERSION} not available"
exit 1
fi
fi
$bash main_program "[email protected]"
Ответ 7
Как мы можем быть уверены, что env существует и даже находится как /usr/bin/env?