Каков рекомендуемый POSIX sh shebang - PullRequest
0 голосов
/ 02 ноября 2018

Я читал, что если вы хотите использовать Bash в переносном режиме, вы должны использовать шебанг:

#!/usr/bin/env bash

Но теперь мне интересно: когда я хочу прямо заявить, что я не полагаюсь на Bash, а вместо этого написал сценарий, совместимый с POSIX, я должен использовать:

#!/bin/sh

Или здесь #!/usr/bin/env sh предпочтительнее?

Ответы [ 2 ]

0 голосов
/ 30 июня 2019

Я бы сказал, #!/usr/bin/env sh предпочтительнее.

Некоторые переносные конструкции, например, цикл по результатам find, требует, чтобы sh был вызван явно. Рассмотрим этот сценарий:

#!/bin/sh
# ... some commands here ...
find . -exec sh -c '
  for file do
    # ... commands processing "$file" ...
  done' find-sh {} +

Команды в начале будут выполняться /bin/sh, а обработка команд "$file" будет выполняться любым sh, который идет первым в PATH, что может вести себя иначе, чем /bin/sh. Это потенциальный источник неожиданных ошибок. #!/usr/bin/env sh shebang решает эту проблему, так как все команды будут выполняться с помощью sh, который является первым в вашей переменной PATH.

Единственным потенциальным недостатком #!/usr/bin/env sh shebang является тот факт, что /usr может не быть подключен во время вызова сценария. Однако на практике это не должно происходить часто. Внешние программы, часто используемые в переносимых сценариях, такие как awk, также часто встречаются в /usr/bin, поэтому может быть трудно убедиться, что сценарий работает правильно с отключенным /usr. В любом случае

Если вы действительно хотите быть переносимым и не зависеть от монтируемого /usr, вы можете начать свой сценарий следующим образом, чтобы убедиться, что он всегда выполняется sh из PATH, где бы он ни был:

#!/bin/sh
if test X"$SUBSHELL" != X"1"; then
  SUBSHELL=1
  export SUBSHELL
  exec sh "$0" "$@"
  exit 1
fi

# ... your actual script comes here ...

Но, похоже, это немного излишне, поэтому я бы сказал, что #!/usr/bin/env sh шебанг - разумный компромисс.

0 голосов
/ 02 ноября 2018

Формальная перспектива

информативный раздел спецификации POSIX для sh: использование приложения состояния что вы не можете полагаться на исполняемый файл sh, установленный на /bin/sh.

Приложения должны учитывать, что стандарт PATH для оболочки не может быть предполагается либо / bin / sh , либо / usr / bin / sh, и должно быть определяется путем опроса PATH , возвращенного getconf PATH , гарантируя, что возвращаемый путь является абсолютным, а не оболочка встроенная.

Например, чтобы определить местоположение стандартной утилиты sh:

command -v sh

Однако вместо предложения использовать env для использования соответствующего PATH, это предполагает, что сценарии оболочки должны быть изменены во время установки, чтобы использовать полный путь к sh:

Кроме того, в системах, которые поддерживают исполняемые скрипты («#!» конструировать), рекомендуется, чтобы приложения использовали исполняемые скрипты установить их с помощью getconf PATH , чтобы определить путь к оболочке и обновить скрипт "#!" соответственно, как это устанавливается (например, с 1042 * СЭД *).

На практике

В основном я пишу сценарии оболочки POSIX и на практике каждую систему GNU / Linux (На базе Red Hat и Debian) - и другие, такие как Cygwin и OS X - имеет POSIX-совместимый sh либо установлен на /bin/sh, либо доступен в виде программного или жесткая ссылка на этот путь. Мне никогда не нужно было использовать env для обслуживания систем где sh не использует этот путь.

Могут быть некоторые системы Unix, где POSIX-совместимый sh недоступен как /bin/sh. Спецификация POSIX предполагает, что он может быть установлен на некоторые системы как /usr/xpg4/bin/sh. Насколько я понимаю, это (было?) Правда для систем Solaris, где /bin/sh - более ранняя версия оболочки Bourne который предшествует POSIX. В этом случае использование env sh не гарантированно поможет, поскольку он все еще может найти оболочку Bourne (в /bin/sh) перед оболочкой POSIX в /usr/xpg4/bin/sh.

Резюме

Если вы пишете сценарии оболочки POSIX для обычных операционных систем Unix и Linux системы, просто используйте #!/bin/sh как shebang.

В редких случаях, когда /bin/sh представляет собой оболочку Bourne вместо POSIX-совместимой shell, вам придется изменить Shebang, чтобы использовать соответствующий полный путь в оболочку POSIX.

В любом случае, использование #!/usr/bin/env sh не имеет смысла - и будет больше шансов потерпеть неудачу, чем просто использовать #!/bin/sh.

...