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



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



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



#!/usr/bin/env bash

#!/usr/bin/env python

#!/usr/bin/env python3




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



Основная идея 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. Ничего сложного. Но на практике обычно никто такой хераборой не занимается. Чисто для примера, ну или для совсем уж костылей, когда нужно быстро и вчера.



Преимущества c 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 и погнали, пока всегда и везде работало. Конец!



tags: #bash #linux



💩 @bashdays