Чому #! / Usr / bin / env bash перевершує #! / Bin / bash?


212

Я бачив в ряді місць, в тому числі рекомендації на цьому сайті ( Що переважне Bash притон? ), Щоб використовувати #!/usr/bin/env bashв перевазі #!/bin/bash. Я навіть бачив, як один заповзятливий чоловік припускає, що використання #!/bin/bashбуло неправильним, і функція bash була б втрачена тим самим.

Все, що сказано, я використовую bash у жорстко контрольованому тестовому середовищі, де кожен привід в обігу по суті є клоном одного головного приводу. Я розумію аргумент переносимості, хоча це не обов'язково застосовується в моєму випадку. Чи є якась інша причина віддавати перевагу #!/usr/bin/env bashальтернативам, і, якщо припустити, що портативність викликає занепокоєння, чи є якась причина, коли її використання може порушити функціональність?


7
Це не обов'язково краще. Дивіться це запитання та мою відповідь на unix.stackexchange.com. (Я хотів би проголосувати, щоб закрити це як дублікат, але я не думаю, що ви можете це робити на сайтах.)
Кіт Томпсон,

2
Окрім відповіді @ zigg, вона envможе не розміщуватися на /usr/bin. Коментарі Shebang - це взагалі погана ідея IMHO. Якщо ваш інтерпретатор сценаріїв за замовчуванням не обробляє коментарі shebang, це лише коментар. Однак, якщо ви знаєте, що інтерпретатор скриптів може обробляти коментарі shebang, і ви знаєте шлях до баш, немає ніяких причин не викликати його, використовуючи його абсолютний шлях, якщо шлях занадто довгий (малоймовірний), або, можливо, ви зможете перенести скрипт до системи, яка не має bash, розташований у / bin. Знову ж таки, застереження, про які я згадував раніше, застосовуються в тому випадку, оскільки це передбачає переносимість.

1
@KeithThompson, дякую за посилання. Можливо, мій пошук відповіді перед тим, як ставити запитання, був трохи вузьким. Мій відвід у всьому цьому: (1) Linux / unix / posix / тощо ... сірий, і (2) кожен, хто претендує на абсолютно правильну відповідь, абсолютно має правильну відповідь для свого конкретного сценарію.
spugm1r3

3
Поведінка багатьох речей в POSIX / Unix добре визначена. Місця розташування не завжди настільки чіткі. Щось повинно існувати як /etcабо /bin/sh. bashє доповненням для більшості подібних систем Unix. Є лише Linux, де bashгарантовано є, /binі, швидше за все, також пов'язаний як /bin/sh. З тих пір, як Linux став сучасним Unix для багатьох людей, той факт, що можуть існувати інші системи, крім Linux, був забутий. У власній відповіді нижче я припустив Linux, тому що ви сказали bash. У багатьох BSD коробках, з якими я працював, навіть не було встановлено.
Шон Перрі

2
@Keith - У випадку з Bash (на відміну від Python в інших питаннях) ... OpenBSD не має /bin/bash. Bash не встановлений за замовчуванням. Якщо ви цього хочете, ви повинні pkg install bash. Після встановлення він знаходиться за адресою /usr/local/bin/bash. На /bin/bashOpenBSD нічого не встановлено . Шебанг #!/bin/bashволі помилиться, і #!/usr/bin/env bashце вдасться.
jww

Відповіді:


229

#!/usr/bin/envпошук PATHпо bash, і bashне завжди /bin, особливо в системах , відмінних від Linux. Наприклад, у моїй системі OpenBSD він є /usr/local/bin, оскільки він був встановлений як необов'язковий пакет.

Якщо ви абсолютно впевнені bash, що /binбудете і завжди будете, немає шкоди, якщо ввести це безпосередньо у свій шебанг - але я б рекомендував проти цього, оскільки всі сценарії та програми живуть поза тим, що ми спочатку вважаємо, що вони матимуть.


29
як щодо envмісця розташування? POSIX не примушує його.
Хуліо Гуерра

1
@JulioGuerra Настільки, як наявність /usr/lib/sendmail(або останнім часом /usr/sbin/sendmail) бінарних файлів, доступних для обробки пошти, це в інтересах Unix, як найкраща система, /usr/bin/envоскільки env shebang - це така поширена практика. Це фактично стандартний інтерфейс.
zigg

8
@zigg Це так UN * X ... <-: Я маю на увазі, що в їх інтересах є стандартне розташування для env, але якось не стандартне місце розташування (яке може бути просто м'яким посиланням) для bash. Не кажучи вже про те, чому тоді хешбанг не приймає просто #!bash, а використовує PATH, замість того , щоб ми робили саме так env. Мабуть, не заплутаний для новобранців.
декани

1
@JulioGuerra Згідно з wikipedia ви правдиві: це не "гарантовано". Натомість це здається "більш імовірним". Wikipedia каже This mostly works because the path /usr/bin/env is commonly used for the env utilityтут en.wikipedia.org/wiki/Shebang_(Unix) - Ми повинні довіритися envтому, що там "напевно" є у всіх системах.
Хаві Монтеро

2
@XaviMontero: Я використовував систему, де envбув /bin, а не в /usr/bin(не впевнений, який саме, ймовірно, SunOS 4). Цього дня це, швидше за все, /usr/bin/envбуде доступно, саме через популярність #!/usr/bin/envхака.
Кіт Томпсон

39

Стандартне розташування bash є /bin, і я підозрюю, що це справедливо для всіх систем. Однак, що робити, якщо вам не подобається ця версія bash? Наприклад, я хочу використовувати bash 4.2, але bash на моєму Mac є в 3.2.5.

Я можу спробувати перевстановити bash, /binале це може бути поганою ідеєю. Якщо я оновлю ОС, вона буде перезаписана.

Однак я міг би встановити bash in /usr/local/bin/bashі встановити PATH для:

PATH="/usr/local/bin:/bin:/usr/bin:$HOME/bin"

Тепер, якщо я вказую bash, я отримую не старий сирий /bin/bash, а новий, блискучий /usr/local/bin. Приємно!

За винятком моїх скриптів оболонок, які мають цей !# /bin/bashшебанг. Таким чином, коли я запускаю сценарії оболонки, я отримую таку стару і паршиву версію bash, яка навіть не має асоціативних масивів.

Використання /usr/bin/env bashвикористовуватиме версію bash, знайдену в моєму PATH. Якщо я встановив свій PATH, щоб він /usr/local/bin/bashбув виконаний, це баш, який будуть використовувати мої сценарії.

Це рідко можна побачити з bash, але це набагато частіше з Perl та Python:

  • Деякі версії Unix / Linux, орієнтовані на стабільність , іноді відстають від випуску цих двох мов сценарію. Не так давно Perl RHEL був у 5,8,8 - восьмирічній версії Perl! Якщо хтось хотів використовувати більш сучасні функції, вам довелося встановити власну версію.
  • Такі програми, як Perlbrew та Pythonbrew, дозволяють встановлювати кілька версій цих мов. Вони залежать від сценаріїв, які маніпулюють вашим PATH, щоб отримати бажану версію. Жорсткий кодування шляху означає , що я не можу запустити мій сценарій під варіння .
  • Не так давно (гаразд, це було давно), що Perl і Python не були стандартними пакетами, що входять до більшості систем Unix. Це означало, що ви не знаєте, де встановлені ці дві програми. Це було під /bin? /usr/bin? /opt/bin? Хто знає? Використання #! /usr/bin/env perlозначало, що я не повинен був знати.

І тепер, чому ви не повинні використовувати #! /usr/bin/env bash

Коли шлях у шебангу твердо кодований, я повинен бігти з цим перекладачем. Таким чином, #! /bin/bashзмушує мене використовувати встановлену за замовчуванням версію bash. Оскільки функції bash дуже стабільні (спробуйте запустити 2.x версію сценарію Python під Python 3.x), дуже малоймовірно, що мій конкретний сценарій BASH не працюватиме, і оскільки мій bash скрипт, ймовірно, використовується цією системою та іншими системами , використання нестандартної версії bash може мати небажані наслідки. З великою ймовірністю я хочу переконатися, що стабільна стандартна версія bash використовується з моїм сценарієм оболонки. Таким чином, я, мабуть, хочу чітко кодувати шлях у моєму шебангу.


5
Це неправда: "Стандартне розташування bash - це / bin" (якщо ви не можете навести стандартний документ), можливо, більш точним є те, що це "звичайне" місце розташування для більшості дистрибутивів Linux і macos, але це не стандарт для систем Unix в цілому (і це, зокрема, не місце розташування більшості * bsds).
tesch1

13

Для виклику bashце небагато зайвих наборів. Якщо у вас є кілька bashбінарних файлів, як ваш власний в ~ / bin, але це також означає, що ваш код залежить від $ PATH, що має в ньому правильні речі.

Це зручно для таких речей, як pythonхоча. Існують сценарії обгортки та середовища, які призводять до використання альтернативних pythonбінарних файлів.

Але нічого не втрачається, використовуючи точний шлях до бінарного, якщо ви впевнені, що це бінарне, якого ви дійсно хочете.


Місце на python. Я втратив підрахунок кількості місць, які pythonможна знайти 😀
zigg

2
Погодилися, що /usr/bin/envкорисніше для Python, особливо якщо ви використовуєте virtualenv.
Денніс

10

Існує багато систем, у яких немає Bash /bin, FreeBSD та OpenBSD, щоб назвати лише декілька. Якщо ваш сценарій призначений для перенесення для багатьох Unices, ви можете використовувати його #!/usr/bin/env bashзамість #!/bin/bash.

Зауважте, що це не відповідає дійсності sh; для Bourne-сумісних скриптів я використовувати виключно #!/bin/sh, так як я думаю , що майже кожен Unix існує має shв /bin.


/binЯ бачу в Ubuntu 18.04 dir sh -> dash. Символічно пов'язаний з dash, виявляючи характер Debian Ubuntu. Запуск цих трьох командних рядків , щоб зрозуміти , що все зводиться до особистих вподобань: which bashто which shпотім which dash.
noobninja

0

Я вважаю за краще обгортати основну програму в сценарій, як показано нижче, щоб перевірити всі 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 "$@"

0
 #!/usr/bin/env bash

це, безумовно, краще, тому що він знаходить виконавчий шлях bash від змінної вашого системного середовища.

Перейдіть до своєї оболонки та введіть Linux

env

Він надрукує всі ваші змінні середовища.

Перейдіть до сценарію оболонки та введіть

echo $BASH

Він надрукує ваш шлях bash (відповідно до списку змінних оточуючих середовищ), який ви повинні використовувати для створення правильного шляху shebang у вашому сценарії.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.