Коли я повинен використовувати #! / Bin / bash, а коли #! / Bin / sh?


104

Коли це #!/bin/bashбільше, ніж #!/bin/shу сценарії оболонки?


55
Коли ви використовуєте bashфункції та синтаксис, а не shфункції та синтаксис.
Мокубай


3
Якщо це допомагає комусь, я помітив, що vimпідкреслить bash-изми, якщо у вашому сценарії є #!/bin/shшебанг. Я змінюю це лише у тому bashвипадку, якщо речі стають досить волохатими, щоб почати потребувати bash-особливостей.
SeldomNeedy

@SeldomNeedy Деякі речі, які він виділяє за замовчуванням, добре працюють у будь-якій оболонці POSIX. $(...)особливо неприємно. Також деякі з них є тонкими [ <(...)і cmd >& fileне отримують жодних помилок підкреслення, наприклад, у них просто немає спеціального виділення для того, що вони означають, з або без g:is_bash]
Random832

@ Random832 Схоже, що останнім часом у цій програмі-випуску vim відбулася деяка активність на цю тему .
SeldomNeedy

Відповіді:


150

Коротко:

  • Існує кілька оболонок, які реалізують надмножину специфікації POSIX sh . У різних системах /bin/shможе бути посилання на ash, bash, dash, ksh, zsh, & c. (Хоча це завжди буде сумісно з sh - ніколи не csh чи fish.)

  • Поки ви дотримуєтесь shлише функцій, ви можете (і, мабуть, навіть повинні) використовувати, #!/bin/shі сценарій повинен працювати добре, незалежно від того, що це оболонка.

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

  • Навіть якщо сценарій призначений лише для особистого використання, ви можете помітити, що деякі ОС змінюються /bin/shпід час оновлення - наприклад, на Debian він раніше був баш, але пізніше був замінений на дуже мінімальний тире. Сценарії, які використовували башизми, але #!/bin/shраптом зламалися.

Однак:

  • Навіть #!/bin/bashне дуже коректно. У різних системах, Баш може жити /usr/binабо /usr/pkg/binабо /usr/local/bin.

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


10
Гарна відповідь. Ви мали на увазі зробити це CW?
Мокубай

3
Лише зауваження, якщо bash запускається звідти, /bin/shвін намагатиметься імітувати shфункції (див. Man сторінку ), не впевнені, що в цьому режимі наявні специфічні функції bash. envtool - це інструмент posix, який слід знайти в більшості дистрибутивів, але я не впевнений, оскільки деякі можуть не поважати posix.
Бріс

8
Ні, насправді POSIX конкретно стверджує, що не можна вважати, що він знаходиться в /bin: " Програми повинні зазначити, що стандартний PATH для оболонки не може вважатись або / bin / sh або / usr / bin / sh, і його слід визначати шляхом допиту PATH, повернутого getconf PATH, гарантуючи, що повернене ім'я шляху є абсолютним іменем шляху, а не вбудованою оболонкою ". Дивіться також це питання, а саме цю відповідь .
тердон

12
Так, це означає, що POSIX насправді не визначає портативний спосіб #!роботи сценаріїв?
grawity

4
POSIX sh - це не Борн: це скоріше похідне раннього ksh, ніж прямий нащадок Борна. Розрізнити їх легко: echo foo ^ catвипускає foo ^ catв POSIX sh, а випускає лише fooв Bourne (як там ^є символ труби).
Чарльз Даффі

18

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

Враховуйте це: якщо ви виходите, #!/bin/bashа ваші користувачі цього не мають, вони побачать чітке повідомлення про помилку, щось подібне

Error: /bin/bash not found

Більшість користувачів можуть виправити це протягом однієї хвилини, встановивши відповідний пакет. З іншого боку, якщо ви заміните shebang на #!/bin/shі протестуєте його в системі, де /bin/shє симпосилання /bin/bash, ваші користувачі, які цього не мають, bashбудуть мати проблеми. Вони, швидше за все, побачать загадкове повідомлення про помилку, наприклад:

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

Це може зайняти години, щоб виправити, і підказки про те, яку оболонку вони мали використовувати, не буде.

Існує не так багато причин, чому ви хочете використовувати іншу оболонку в шебангу. Однією з причин є те, коли використовувана вами оболонка не має широкого поширення. Ще один - отримати продуктивність, shяка значно швидша в деяких системах, і ваш сценарій буде вузьким місцем продуктивності. У цьому випадку ретельно протестуйте свій скрипт із цільовою оболонкою, а потім змініть шебанг.


@Hastur Я не отримую твого коментаря. Shebang неодмінно визначить, яка оболонка буде використовуватися для запуску сценарію, ви вважаєте, моя відповідь має на увазі інакше?
Дмитро Григор'єв

1
Забудь це. Я неправильно зрозумів частину "чому ти хотів би використати" ...
Хастур

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 або щось подібне, немає нічого поганого в тому, щоб залишити їх як скрипти оболонки. Але прості сценарії оболонки не потребують масивів чи функцій чи [[навіть. І ви повинні писати складні сценарії оболонки лише тоді, коли у вас немає іншого вибору. Наприклад, сценарії автозапуску, як правило, все ще є сценаріями оболонки. Але ці сценарії повинні працювати на кожному втіленні, /bin/shщо стосується програми, яка налаштована. а це означає, що вони не можуть використовувати будь-які розширення. Напевно, вам не доведеться піклуватися про старі власні Unixes в наші дні, але вам, мабуть, слід подбати про поточні BSD з відкритим кодом, деякі з яких не встановлюютьсяbashза замовчуванням та вбудовані середовища, які дають лише мінімальний оболонку та busybox.

На закінчення відзначимо , що момент , коли ви опиняєтеся бажаючи особливість , яка недоступна в портативному мовою оболонки, що є ознакою того, що сценарій став занадто складним , щоб залишитися скрипт. Перепишіть її замість кращої мови.


4
Вибачте, але це трохи нерозумно. Так, якщо ви пишете щось, що буде i) розповсюджене і ii) в різних середовищах, вам слід дотримуватися основного sh. Це, однак, далеко не те, що ви ніколи не повинні використовувати інші снаряди. Є щодня тисячі (ймовірно, ще багато) сценаріїв, і переважна більшість з них коли-небудь працюватиме на одній машині. Ваша порада має сенс щодо виробничого коду, але не для щоденних "системних" завдань, для яких написано більшість сценаріїв. Якщо я знаю, що мій сценарій коли-небудь буде використовуватися мною і на машині Linux, баш добре.
тердон

1
@terdon Справа в тому, що якщо у вас є можливість написати скрипт bash, тоді ви також можете написати сценарій perl (або будь-який інший), і це завжди кращий вибір.
zwol

@terdon Відповідь, безумовно, не дурна, ваш коментар натомість просто наївний. Сценарії оболонки страшні для налагодження порівняно з Perl і подібні, для яких можна легко використовувати повний IDE з графічною налагодженням і все. Крім того, більшість сценаріїв, написаних щодня, щоб зробити якісь невеликі речі, як правило, змінювались і змінювались знову, зростали, копіюються як приклади до колег чи в мережі тощо. Найімовірніше, немає причин ризикувати.
Торстен Шьонинг

@ ThorstenSchöning я сказав трохи нерозумно. Якби це Unix і Linux або навіть переповнення стека, я б навіть погодився. Якщо ми говоримо про загальну найкращу практику або про професійних програмістів, звичайно, найкраще дотримуватися базових POSIX sh. Однак це Супер Користувач , сайт, орієнтований на кінцевих користувачів і каже людям ніколи не використовувати bash або zsh при написанні скриптів оболонок, на мій погляд, екстремальний.
тердон

@terdon Це насправді більш важливим, на мій погляд, щоб перешкоджати кінцевих користувачів від написання складних скриптів. Професіонали в середньому мають більш високий рівень кваліфікації (тому вони, швидше за все, зможуть впоратися з підводними каменями складних сценаріїв оболонок), повинні з деякою точністю знати, до яких середовищ вони повинні бути переносними, і їм платять, щоб не здаватися в розчаруванні.
zwol

4

Як правило, якщо час важливіший за функціональність, ви скористаєтеся швидшою оболонкою. sh часто псевдонімується на тире і, як правило, використовується для виконання завдань cron або пакетних операцій, де кожна (нано) секунда враховується.


2
Завантаження інтерпретатора додаткової оболонки з файлової системи може заперечувати таку перевагу, і все, де наносекунди (які знаходяться в тому самому порядку величини, як і фактичний машинний цикл), є доменом програмістів C і мови монтажу.
rackandboneman

Наносекунди можуть змінити роботу лише з кронами, якщо їх у вас мільярди, і cron так і не зможе обробити стільки.
Дмитро Григор’єв

1
Навіть якщо mckenzm трохи перебільшений, не можна заперечувати, що краще мати більшу продуктивність! Не зависайте на "нано" частині. (Наносекунди навіть не враховуються в C, якщо це не внутрішня петля в режимі реального часу або така!)
jpaugh

1
@jpaugh Якщо ви не працюєте зі (застарілою) системою, яка передбачає, що певні операції потребуватимуть принаймні певного періоду часу. Буває!
JAB

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 / щось має бути найбільш вірогідним шляхом для використання.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.