В чем разница между этими двумя операторами в заголовке Bash-скрипта:
#!/usr/bin/env bash#!/usr/bin/bash
Когда я сверился со env справочной страницей , я получил это определение:
env - run a program in a modified environment
Что это значит?
В чем разница между этими двумя операторами в заголовке Bash-скрипта:
#!/usr/bin/env bash
#!/usr/bin/bash
Когда я сверился со env справочной страницей , я получил это определение:
env - run a program in a modified environment
Что это значит?
Ответы:
Выполнение команды сквозной /usr/bin/envимеет преимущество ищет то , что по умолчанию версия программы находится в текущем окр ironment.
Таким образом, вам не нужно искать его в определенном месте в системе, поскольку эти пути могут находиться в разных местах в разных системах. Пока он на вашем пути, он его найдет.
Одним из недостатков является то, что вы не сможете передать более одного аргумента (например, вы не сможете писать /usr/bin/env awk -f), если вы хотите поддерживать Linux, поскольку POSIX неопределен в отношении того, как должна интерпретироваться строка, и Linux интерпретирует все после первого пространство для обозначения одного аргумента. Вы можете использовать /usr/bin/env -Sв некоторых версиях, envчтобы обойти это, но тогда сценарий станет еще менее переносимым и сломается на довольно недавних системах (например, даже Ubuntu 16.04, если не позже).
Другим недостатком является то, что, поскольку вы не вызываете явный исполняемый файл, у него есть вероятность ошибок и проблем с безопасностью многопользовательских систем (например, если кому-то удалось получить вызываемый файл bashна вашем пути).
#!/usr/bin/env bash #lends you some flexibility on different systems
#!/usr/bin/bash #gives you explicit control on a given system of what executable is called
В некоторых ситуациях первое может быть предпочтительным (например, запуск сценариев Python с несколькими версиями Python без необходимости переделки исполняемой строки). Но в ситуациях, когда безопасность находится в центре внимания, последнее предпочтительнее, так как оно ограничивает возможности внедрения кода.
#!/usr/bin/env echo Helloжалуется: /usr/bin/env: echo Hello: No such file or directory. По-видимому, это рассматривается echo Helloкак один аргумент /usr/bin/env.
envкоманда, безусловно, позволяет передавать аргументы команде. Проблема заключается в семантике #!строки, и это зависит от ядра. Последние ядра Linux допускают такие вещи, как #!/usr/bin/env command argsстарые ядра Linux и другие системы.
Использование #!/usr/bin/env NAMEзаставляет оболочку искать первое совпадение NAME в переменной окружения $ PATH. Это может быть полезно, если вы не знаете об абсолютном пути или не хотите его искать.
Вместо того, чтобы явно определять путь к интерпретатору, как /usr/bin/bash/при использовании команды env, интерпретатор ищется и запускается оттуда, где он был впервые найден. Это имеет как плюсы, так и минусы
Если сценарии оболочки начинаются с #!/bin/bash, они всегда будут работать с bashс /bin. Если они однако начать с #!/usr/bin/env bash, они будут искать bashв $PATHи затем начать с первыми они могут найти.
Почему это было бы полезно? Предположим, вы хотите запустить bashсценарии, для которых требуется bash 4.x или новее, но в вашей системе установлена только bash3.x, и в настоящее время ваш дистрибутив не предлагает более новую версию, или вы не являетесь администратором и не можете изменить то, что установлено в этой системе. ,
Конечно, вы можете скачать исходный код bash и создать свой собственный bash с нуля, разместив его, ~/binнапример. И вы также можете изменить свою $PATHпеременную в своем .bash_profileфайле, чтобы включить ~/binв качестве первой записи ( PATH=$HOME/bin:$PATHпоскольку ~не будет расширяться в $PATH). Если вы сейчас позвоните bash, оболочка сначала будет искать его $PATHпо порядку, поэтому она начинается с того места ~/bin, где она найдет ваш bash. То же самое происходит, если скрипты ищут для bashиспользования #!/usr/bin/env bash, поэтому эти скрипты теперь будут работать в вашей системе с использованием вашей пользовательской bashсборки.
Недостатком является то, что это может привести к неожиданному поведению, например, один и тот же сценарий на одном и том же компьютере может работать с разными интерпретаторами для разных сред или пользователей с разными путями поиска, вызывая все виды головной боли.
Самым большим недостатком envявляется то, что некоторые системы допускают только один аргумент, поэтому вы не можете сделать это #!/usr/bin/env <interpreter> <arg>, так как системы будут рассматривать <interpreter> <arg>как один аргумент (они будут обрабатывать его, как если бы выражение было заключено в кавычки) и, таким образом, envбудут искать интерпретатор с именем <interpreter> <arg>. Обратите внимание, что это не проблема самой envкоманды, которая всегда позволяла передавать несколько параметров, но с помощью анализатора shebang системы, которая анализирует эту строку еще до вызова env. Между тем, это было исправлено в большинстве систем, но если ваш скрипт хочет быть сверхпортативным, вы не можете полагаться, что это было исправлено в системе, которую вы будете использовать.
Он может даже иметь последствия для безопасности, например, если sudoон не был настроен для очистки окружающей среды или $PATHбыл исключен из очистки. Позвольте мне продемонстрировать это:
Обычно /binэто хорошо защищенное место, только там rootможно что-то изменить. Ваш домашний каталог, однако, не любая программа, которую вы запускаете, может внести в нее изменения. Это означает, что вредоносный код может поместить фальшивку bashв какой-то скрытый каталог, изменить его, .bash_profileчтобы включить этот каталог в свой $PATH, так что все используемые скрипты в #!/usr/bin/env bashконечном итоге будут работать с этой фальшивкой bash. Если sudoдержится $PATH, у вас большие проблемы.
Например, рассмотрим инструмент, создающий файл ~/.evil/bashсо следующим содержанием:
#!/bin/bash
if [ $EUID -eq 0 ]; then
echo "All your base are belong to us..."
# We are root - do whatever you want to do
fi
/bin/bash "$@"
Давайте сделаем простой скрипт sample.sh:
#!/usr/bin/env bash
echo "Hello World"
Подтверждение концепции (в системе, где sudoхранится $PATH):
$ ./sample.sh
Hello World
$ sudo ./sample.sh
Hello World
$ export PATH="$HOME/.evil:$PATH"
$ ./sample.sh
Hello World
$ sudo ./sample.sh
All your base are belong to us...
Hello World
Обычно все классические оболочки должны быть расположены внутри, /binи если вы не хотите размещать их там по какой-либо причине, на самом деле не является проблемой разместить символическую ссылку, /binкоторая указывает на их реальное местоположение (или, возможно, /binсама является символической ссылкой), поэтому Я бы всегда пошел с #!/bin/shи #!/bin/bash. Слишком много всего сломалось бы, если бы они больше не работали. Дело не в том, что POSIX потребует эти позиции (POSIX не стандартизирует имена путей и, следовательно, он даже не стандартизирует функцию shebang), но они настолько распространены, что даже если система не предлагает /bin/sh, она, вероятно, все еще понимает #!/bin/shи знать, что с ним делать, и может ли это быть только для совместимости с существующим кодом.
Но для более современных, нестандартных, необязательных интерпретаторов, таких как Perl, PHP, Python или Ruby, на самом деле не указано, где они должны быть расположены. Они могут быть в, /usr/binно они могут также находиться в /usr/local/binили в совершенно другой ветви иерархии ( /opt/..., /Applications/...и т. Д.). Вот почему они часто используют #!/usr/bin/env xxxсинтаксис Шебанга.
Я нахожу это полезным, потому что, когда я не знал об env, до того, как начал писать скрипт, я делал это:
type nodejs > scriptname.js #or any other environment
а потом я модифицировал эту строку в файле в shebang.
Я делал это, потому что я не всегда помнил, где находится nodejs на моем компьютере - / usr / bin / или / bin /, поэтому для меня envэто очень полезно. Может быть, есть детали с этим, но это моя причина