#! / Bin / ш против #! / bin / bash для максимальной переносимости

Я обычно работаю с серверами Ubuntu LTS, которые, насколько я понимаю, символическая ссылка / bin / sh на / bin / dash . Множество других дистрибутивов, хотя символическая ссылка / bin / sh на / bin / bash .

Из этого я понимаю, что если сценарий использует #! / bin / sh наверху он может не работать одинаково на всех серверах?

Есть ли предлагаемая практика, какую оболочку использовать для сценариев, если требуется максимальная переносимость этих сценариев между серверами?

36
задан 30 July 2017 в 10:44
3 ответа

Существует примерно четыре уровня переносимости сценариев оболочки (что касается строки shebang):

  1. Наиболее переносимый: используйте #! / bin / sh shebang и использовать только базовый синтаксис оболочки, указанный в стандарте POSIX . Это должно работать практически в любой системе POSIX / unix / linux. (Ну, за исключением Solaris 10 и более ранних версий, в которых была настоящая устаревшая оболочка Bourne, предшествующая POSIX, поэтому она несовместима, как / bin / sh .)

  2. Второй по переносимости: используйте #! / bin / bash (или #! / usr / bin / env bash ) строку shebang и придерживайтесь функций bash v3. Это будет работать в любой системе, в которой есть bash (в ожидаемом месте).

  3. Третий по переносимости: используйте #! / Bin / bash (или #! / Usr / bin / env bash ) shebang и используйте возможности bash v4. Это не сработает в любой системе с bash v3 (например, macOS, которая должна использовать его по причинам лицензирования).

  4. Наименее переносимый: используйте #! / Bin / sh shebang и используйте расширения bash в синтаксис оболочки POSIX. Это не сработает в любой системе, в которой есть что-то, кроме bash для / bin / sh (например, последние версии Ubuntu). Никогда не делай этого; это не просто проблема совместимости, это просто неправильно. К сожалению, эту ошибку делают многие.

Моя рекомендация: используйте наиболее консервативную из первых трех, которая предоставляет все функции оболочки, необходимые для сценария. Для максимальной переносимости используйте вариант №1, но по моему опыту некоторые возможности bash (например, массивы) достаточно полезны, поэтому я выберу №2.

Худшее, что вы можете сделать, это №4, используя неправильный шебанг. Если вы не уверены, какие функции являются базовыми функциями POSIX, а какие - расширениями bash, либо используйте bash shebang (т.е. вариант № 2), либо тщательно протестируйте сценарий с помощью очень простой оболочки (например, dash на ваших серверах Ubuntu LTS). В вики Ubuntu есть хороший список башизмов, на которые следует обратить внимание .

В вопросе о Unix и Linux есть очень хорошая информация об истории и различиях между оболочками «Что это значит для быть sh совместимой? » и вопрос Stackoverflow « Разница между sh и bash ».

Также имейте в виду, что оболочка - не единственное, что различается между разными системами; Если вы привыкли к Linux, вы привыкли к командам GNU, которые имеют множество нестандартных расширений, которые вы можете не найти в других системах Unix (например, bsd, macOS). К сожалению, здесь нет простого правила, вам просто нужно знать диапазон вариаций используемых вами команд.

Одна из самых неприятных команд с точки зрения переносимости - одна из самых простых: echo . Каждый раз, когда вы используете его с любыми параметрами (например, echo -n или echo -e ) или с любыми escape-символами (обратными косыми чертами) в строке для печати, разные версии будут делать разные вещи . Каждый раз, когда вы хотите напечатать строку без перевода строки или с escape-символами в строке, используйте вместо этого printf (и узнайте, как это работает - это сложнее, чем echo . ). Команда ps также беспорядок .

Еще одна общая вещь, на которую следует обратить внимание, - это недавние расширения / GNUish для синтаксиса параметров команды: старый (стандартный) формат команды заключается в том, что за командой следуют параметры (с одним дефисом, и каждая опция представляет собой одну букву), за которыми следуют аргументы команды. Последние (и часто непереносимые) варианты включают длинные параметры (обычно вводятся с помощью - ), позволяющие указывать параметры после аргументов, а также использование - для отделения параметров от аргументов.

65
ответ дан 28 November 2019 в 19:49

В сценарии ./ configure , который подготавливает язык TXR к сборке, я написал следующий пролог для лучшей переносимости. Сценарий сам загрузится, даже если #! / Bin / sh не является POSIX-совместимой старой оболочкой Bourne Shell. (Я создаю каждый выпуск на виртуальной машине Solaris 10.)

#!/bin/sh

# use your own variable name instead of txr_shell;
# adjust to taste: search for your favorite shells

if test x$txr_shell = x ; then
  for shell in /bin/bash /usr/bin/bash /usr/xpg4/bin/sh ; do
    if test -x $shell ; then
       txr_shell=$shell
       break
    fi
  done
  if test x$txr_shell = x ; then
    echo "No known POSIX shell found: falling back on /bin/sh, which may not work"
    txr_shell=/bin/sh
  fi
  export txr_shell
  exec $txr_shell $0 ${@+"$@"}
fi

# rest of the script here, executing in upgraded shell

Идея здесь в том, что мы находим лучшую оболочку, чем та, в которой мы работаем, и повторно выполняем сценарий с использованием этой оболочки. Переменная среды txr_shell установлена, так что повторно выполняемый сценарий знает, что это повторно выполненный рекурсивный экземпляр.

(В моем сценарии переменная txr_shell также впоследствии используется ровно для двух целей: во-первых, он печатается как часть информационного сообщения в выводе скрипта. Во-вторых, он устанавливается как переменная SHELL в Makefile , поэтому make также будет использовать эту оболочку для выполнения рецептов.)

В системе, где / bin / sh - тире, вы можете видеть, что приведенная выше логика найдет / bin / bash и повторно выполните сценарий с этим.

В системе Solaris 10 / usr / xpg4 / bin / sh сработает, если Bash не найден.

Пролог написан на консервативном диалекте оболочки с использованием теста для проверки существования файлов и трюка $ {@ + "$ @"} для расширения аргументов, обслуживающих некоторые нарушенные старый s ад (что было бы просто "$ @" , если бы мы были в оболочке, соответствующей POSIX).

5
ответ дан 28 November 2019 в 19:49

Все вариации языка оболочки Борна объективно ужасны по сравнению с современными скриптовыми языками, такими как Perl, Python, Ruby, node.js и даже (возможно) Tcl. Если Вам приходится делать что-то даже немного сложное, Вы будете счастливее в долгосрочной перспективе, если будете использовать один из вышеперечисленных языков вместо скриптов оболочки.

Единственное преимущество, которое язык оболочки все еще имеет перед этими новыми языками, это то, что что-то , называющее себя /bin/sh, гарантированно существует на всем, что претендует на Unix. Однако, что-то может даже не быть POSIX-совместимым; многие из старых проприетарных Unixs заморозили язык, реализованный /bin/sh и утилиты в PATH по умолчанию до изменений, требуемых Unix95 (да, Unix95, двадцать лет назад и считая). Может быть набор Unix95, или даже POSIX.1-2001, если повезет, утилиты в каталоге , а не на PATH по умолчанию (например, /usr/xpg4/bin), но их существование не гарантируется.

Однако, основы Perl - это более вероятно присутствие в произвольно выбранной инсталляции Unix, чем Bash. (Под "основами Perl" я подразумеваю, что /usr/bin/perl существует и является некоторой , возможно довольно старой, версией Perl 5, и если вам повезет, набор модулей, которые поставляются с этой версией интерпретатора, также доступен). Поэтому:

Если вы пишете что-то, что должно работать везде , что претендует на Unix (например, скрипт "configure"), вы должны использовать #! /bin/sh, и вам не нужно использовать никаких расширений. Сейчас я бы написал оболочку, соответствующую POSIX.1-2001, но я был бы готов исправить POSIXism'ы, если бы кто-нибудь попросил поддержки ржавого железа.

Но если вы не пишете что-то, что должно работать везде, то в тот момент, когда вы искушаетесь использовать любой Башизм вообще, вы должны остановиться и переписать все это на более подходящем языке сценариев. Ваше будущее "Я" вас отблагодарит.

(Так когда будет уместно использовать расширения Bash? Для первого порядка: никогда. Во втором порядке: только для расширения интерактивной среды Bash - например, для предоставления умных табуляций и причудливых подсказок)

.
2
ответ дан 28 November 2019 в 19:49

Теги

Похожие вопросы