101

Когда это #!/bin/bash более уместен, чем #!/bin/sh в скрипте оболочки?

6 ответов6

147

Короче:

  • Существует несколько оболочек, которые реализуют расширенный набор спецификации POSIX sh. В разных системах /bin/sh может быть ссылкой на ash, bash, dash, ksh, zsh, & c. (Это всегда будет совместимо с sh - никогда не csh или fish.)

  • Пока вы придерживаетесь только функций sh , вы можете (и, вероятно, даже должны) использовать #!/bin/sh и скрипт должен работать нормально, независимо от того, какая это оболочка.

  • Если вы начнете использовать специфичные для bash функции (например, массивы), вам следует специально запросить bash - потому что, даже если /bin/sh уже вызывает bash в вашей системе, это может произойти не во всех остальных системах, и ваш скрипт не будет работать там. (То же самое относится и к zsh и ksh.) Вы можете использовать shellcheck для идентификации bashisms.

  • Даже если скрипт предназначен только для личного использования, вы можете заметить, что некоторые ОС меняют /bin/sh во время обновлений - например, в Debian он был bash, но позже был заменен на очень минимальный тире. Скрипты, которые использовали bashisms, но имели #!/bin/sh внезапно сломался.

Тем не мение:

  • Даже #!/bin/bash не очень правильно. В разных системах bash может находиться в /usr/bin или /usr/pkg/bin или /usr/local/bin .

  • Более надежный вариант #!/usr/bin/env bash, который использует $ PATH. (Хотя сам инструмент env строго не гарантирован, /usr/bin/env прежнему работает на большем количестве систем, чем /bin/bash .)

18

Используйте шебанг, соответствующий оболочке, которую вы фактически использовали для разработки и отладки вашего скрипта. Т.е., если ваша оболочка входа в систему bash , и вы запускаете свой скрипт как исполняемый файл в вашем терминале, используйте #!/bin/bash . Не просто предполагайте, что, поскольку вы не использовали массивы (или какую-либо другую функцию bash которой вам известно), вы можете выбрать любую оболочку, которая вам нравится. Есть много тонких различий между оболочками (echo , функции, циклы, вы называете это), которые не могут быть обнаружены без надлежащего тестирования.

Учтите это: если вы уйдете #!/bin/bash и ваши пользователи не имеют его, они увидят четкое сообщение об ошибке, что-то вроде

Error: /bin/bash not found

Большинство пользователей могут исправить это за одну минуту, установив соответствующий пакет. С другой стороны, если вы замените Шебанг на #!/bin/sh и протестируйте его в системе, где /bin/sh является символической ссылкой на /bin/bash , у ваших пользователей, у которых нет bash будут проблемы. Скорее всего, они увидят загадочные сообщения об ошибках, такие как:

Error in script.sh line 123: error parsing token xyz

Это может занять несколько часов, и не будет никакого понятия о том, какую оболочку они должны были использовать.

Существует не так много причин, по которым вы захотите использовать другую оболочку в shebang. Одна из причин заключается в том, что используемая вами оболочка не получила широкого распространения. Другой способ - повысить производительность с помощью sh который в некоторых системах значительно быстрее, и ваш сценарий станет узким местом в производительности. В этом случае тщательно протестируйте свой сценарий с помощью целевой оболочки, а затем измените shebang.

6

Вы должны только когда-либо использовать #! /bin/sh .

Вы никогда не должны использовать расширения bash (или zsh, или fish, или ...) в сценарии оболочки.

Вы должны когда-либо писать сценарии оболочки, которые работают с любой реализацией языка оболочки (включая все "служебные" программы, которые идут вместе с самой оболочкой). В эти дни вы, вероятно, можете считать POSIX.1-2001 (не -2008) авторитетным для того, на что способны оболочка и утилиты, но имейте в виду, что однажды вас могут попросить перенести ваш скрипт на устаревшую систему (например, Solaris или AIX), чьи оболочки и утилиты были заморожены около 1992 года.

Что, серьезно ?!

Да серьезно.

Вот в чем дело: Shell - ужасный язык программирования. Единственное, что у него есть, это то, что /bin/sh - это единственный интерпретатор сценариев, который гарантированно будет в каждой установке Unix.

Вот еще одна вещь: некоторая итерация основного интерпретатора Perl 5 (/usr/bin/perl) более вероятно будет доступна в случайно выбранной установке Unix, чем (/(usr|opt)(/(local|sfw|pkg)?)?/bin/bash есть. Другие хорошие скриптовые языки (Python, Ruby, node.js и т.д. - я даже включу PHP и Tcl в эту категорию при сравнении с оболочкой) также примерно так же доступны, как bash и другие расширенные оболочки.

Поэтому, если у вас есть возможность написания bash-скрипта, у вас есть возможность использовать не просто ужасный язык программирования.

Теперь, простые сценарии оболочки, такие, которые запускают несколько программ последовательно из задания cron или чего-то еще, нет ничего плохого в том, чтобы оставить их как сценарии оболочки. Но простым сценариям оболочки не нужны массивы или функции или [[ даже. И вы должны писать сложные сценарии оболочки только тогда, когда у вас нет другого выбора. Например, сценарии Autoconf по-прежнему являются сценариями оболочки. Но эти сценарии должны запускаться при каждом воплощении /bin/sh которое имеет отношение к конфигурируемой программе. и это означает, что они не могут использовать какие-либо расширения. Возможно, вам не нужно заботиться о старых проприетарных Unix-файлах в наши дни, но вам, вероятно, следует позаботиться о текущих BSD с открытым исходным кодом, некоторые из которых не устанавливают bash по умолчанию, и встроенных средах, которые предоставляют вам только минимальную оболочку и busybox ,

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

4

Обычно, если время важнее, чем функциональность, вы используете более быструю оболочку. sh часто имеет псевдоним dash и, как правило, используется для задач cron root или пакетных операций, где учитывается каждая (нано) секунда.

3

Чтобы быть еще более кратким, используйте sh если переносимость между большинством систем наиболее важна, и bash если вы хотите использовать некоторые его специфические функции, такие как массивы, если версия bash поддерживает это.

1
  • sh (в большинстве случаев), bash, если требуется (или ksh, или что-то еще)

Самый безопасный путь. когда он жестко запрограммирован, будет /usr /bin /shellOfChoice но новое соглашение, которое я пытаюсь использовать всегда, так как «местоположение по умолчанию» при изменении PATH может измениться так:

#!/usr/bin/env sh или
#!/usr/bin/env bash
или, например, Perl-скрипты
#!/usr/bin/env perl -w

Конечно, когда у вас есть причина, по которой скрипт НИКОГДА не будет автоматически принимать новый PATH, продолжайте жестко его кодировать, и тогда /usr /bin / что-то должно быть наиболее вероятным путем для использования.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .