Тишина у каждого своя, у всех в душе свои оркестры…

Как мы с тобой знаем, в начале скрипта принято использовать строку shebang/hashbang. Это то самое, которое #!/bin/bash. Конечно его не обязательно ставить, но рекомендуется. Ранее этот вопрос разбирался здесь.

Так, но порой вместо привычной нам конструкции, можно встретить нечто подобное:

#!/usr/bin/env bash
#!/usr/bin/env python
#!/usr/bin/env python3

Да, с питончиком тоже такая чача бывает. Но что это за сракафак и зачем? В нашем случае такое хитрое указание интерпретатора имеет смысл.

Роман Шубин
Роман Шубин
CEO & CTO, Главред в «Цифровой улей»
Задать вопрос
Основная идея env bash это улучшение переносимости. Никто не может гарантировать, что интерпретатор находится по захардкоженному пути.

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

Ну и используя env в скрипте можно указывать любые версии интерпретатора. Возможно у тебя стоит две версии bash, ну или как распространено с питончиком. Деприкейтед 2.7 и трёшка. Думаю мысль ты уловил. Чтобы не править скрипты, можно подменять версии интерпретаторов и даже сами интерпретаторы.

Давай посмотрим на практике.

mkdir ~/bin
cp /bin/sh ~/bin/bash
export PATH=~/bin:$PATH
env bash
  1. Создаем папку bin в домашнем каталоге
  2. Копируем интерпретатор sh в ~/bin, но обзываем его bash
  3. Экспортируем новый путь ~/bin в PATH
  4. Запускаем bash через env

Дела… у нас запустился интерпретатор sh. То есть ~/bin/bash (обращаем внимание на знак ~ = домашняя директория пользователя) был найден раньше, чем просто /bin/bash.

Если посмотреть PATH мы увидим следующее:

echo $PATH
/root/bin:/root:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

Наш домашний каталог с бинарниками стал приоритетным. И если теперь в скриптах указать #!/usr/bin/env bash то запустится sh из ~/bin. Ничего сложного. Но на практике обычно никто такой хераборой не занимается. Чисто для примера, ну или для совсем уж костылей, когда нужно быстро и вчера.

Преимущества с env:

  • Запуск интерпретатора не из конкретно указанного места, а из того что встретилось первым в переменной окружения PATH.

Недостатки:

  • Путь /usr/bin/env банально может не существовать. Но обычно существует.

Ну и если используешь env, в него можно прокинуть параметры, делается через ключик -S:

#!/usr/bin/env -S var1=a var2=b bash --help

Venv в Python работает по такому же принципу, реврайтит PATH и позволяет использовать разные версии.

> index.py
python3 -m venv .venv
source .venv/bin/activate
import sys
print(sys.executable)

/tmp/.venv/bin/python

Если посмотреть PATH (echo $PATH) при активации venv, то увидим совершенно другой PATH:

/tmp/.venv/bin:/home/user/bin:/usr/local/opt/libpcap/bin:/home/user/.pyenv/bin:/opt/homebrew/opt/openjdk/bin

То есть к нашему PATH добавился каталог /tmp/.venv/bin, который стал приоритетнее чем /home/user/bin.

Вот так вот это всё и работает под капотом. Я эти env по большей части никогда не использую, хреначу #!/bin/bash и погнали, пока всегда и везде работало. Конец!