Какая разница в использовании #!/Usr/bin/env или #!/Bin/env в shebang?

Будет ли какая-то разница или это просто личный выбор?

Ответ 1

#!<interpreter> <arguments> пытается запустить <interpreter> <arguments>, чтобы прочитать и запустить остальную часть файла.

Итак, #!/usr/bin/env означает, что должна быть программа с именем /usr/bin/env; #!/bin/env означает, что должна быть программа под названием /bin/env.

В некоторых системах есть один, а не другой.

По моему опыту, большинство из них имеют /usr/bin/env, поэтому #!/usr/bin/env чаще встречается.

Unix-системы попытаются запустить <interpreter> с помощью execve, поэтому он должен быть полным путем, а #!env без пути не будет работать.

Ответ 2

Объяснение Микеля велико, оно пропускает только небольшой факт (что весьма важно), он пропускает только один аргумент, включая все пробелы:

#!<Interpreter> <argument>

Результаты при вызове:

$ <Interpreter> '<argument>' path_to_calling_script

Итак, для примера:

$ cat /tmp/test
#!/usr/bin/env python
print "hi"

$ /tmp/test

совпадает с вызовом:

$ /usr/bin/env "python" /tmp/test

Кавычки пытаются показать, что если вы добавите какой-либо флаг или другие значения, это будет часть вызываемого аргумента.

 #!/bin/bash -c /bin/env python

Будет интерпретироваться как:

 $ /bin/bash "-c /bin/env python"

Что не будет работать.

Ответ 3

/usr/bin/env является мягкой ссылкой на /bin/env. По существу, вы используете /bin/env

Ответ 4

Исторически в UNIX было 2 набора двоичных файлов:

  • / Файловая система смонтирована в начале загрузки.
  • Возможно, /usr был смонтирован позже, возможно, запустив сценарии и программы из / для организации монтирования. Пример: некоторые сайты сэкономили место, подключив /usr из сети, но сначала вам нужно войти в сеть. Пример: это большая локальная файловая система, но если она повреждена, вы хотите, чтобы такие инструменты, как fsck попытались ее исправить.

Таким образом, /bin и /sbin (используя /lib) должны были содержать минимальную систему, включающую по крайней мере оболочку в /bin/sh, основы сценариев, такие как /bin/echo, /bin/test и т.д., Системные инструменты, такие как /bin/mount или /sbin/mount и /bin/fsck...

Таким образом, в разных Unix-системах практически любая программа могла быть:

  • в /usr/bin/но НЕ /bin
  • в /bin, но НЕ /usr/bin
  • в обоих, так же, как символическая ссылка
  • в обоих но разные! Например, в некоторых системах игра /bin/sh является очень минимальной оболочкой (например, dash) для более быстрого запуска, но символическая ссылка /usr/bin/sh/usr/bin/bash (iirc, вызывая bash как "sh", помещает его в какой-то режим posix, но это все же другая более мощная оболочка).

Таким образом, хитрость использования env для написания переносимых скриптов - env просто делает поиск в PATH. (Это также полезно в других местах, которые не выполняют поиск PATH, например, docker exec.)

Что изменилось

Это были действительные случаи использования, но современный Linux последовал подобный аргументу "нужен небольшой UserSpace для монтирования/восстановления основного UserSpace" для / себя тоже! Были введены сводный системный вызов и initrd, и выросли инструменты для копирования в него нужных вам частей.

/usr унификация

Теперь / vs /usr возможно, утратил свою цель. И то, и другое на одной файловой системе и символических ссылках было выполнимо для всех в принципе, хотя некоторые конкретные установки сломались бы и должны были измениться...

См. Https://lwn.net/Articles/483921/ с 2012 года для обзора этой идеи "/usr unification". Например, Fedora завершила это: https://fedoraproject.org/wiki/Features/UsrMove. Многие другие дистрибутивы не имеют или все еще обсуждают его, или сглаживают некоторые виды, чтобы сломать меньше пользователей. Например, смотрите подготовку к Debian: https://wiki.debian.org/UsrMerge.