Чи правильно використовувати / bin / sh в хешбангу, якщо оболонка Bourne недоступна в дистрибутиві?


15

Як правило, сценарії оболонки містять наступний коментар в першому рядку файлу сценарію: #!/bin/sh. Відповідно до проведених нами досліджень, це називається "хеш-баг", і це умовний коментар. Цей коментар повідомляє Unix, що цей файл виконується штурмом Bourne під каталогом /bin.

Моє запитання починається з цього моменту. Досі такого коментаря я не бачив #!/bin/bash. Це завжди #!/bin/sh. Однак у дистрибутивах Ubuntu немає програми Bourne Shell. Вони мають оболонку Bourne Again (баш).

У цьому пункті, чи правильно розміщувати коментар #!/bin/shу скриптах оболонок, написаних у дистрибутивах Ubuntu?



1
Дивіться мою відповідь на це серверне запитання за замовчуванням: #! / Bin / sh vs #! / Bin / bash для максимальної мобільності .
Гордон Девіссон

Найчастіше називаютьshebang
fpmurphy

Відповіді:


16

#!/bin/shмає працювати над усіма Unix та Unix-подібними дистрибутивами. Як правило, це вважається найбільш портативним хешбангом, якщо ваш сценарій підтримується POSIX сумісним. /bin/shОболонка повинна бути оболонкою , яка реалізує POSIX оболонки стандарту, незалежно від того, що фактична оболонки є те , що маскарад як /bin/shоболонки.


#!/bin/shзазвичай це лише посилання, оскільки оболонка Борна більше не підтримується. У багатьох системах Unix /bin/shбуде посилання на /bin/kshабо /bin/ashна багатьох системах Linux на базі RHEL, воно буде посиланням /bin/bash, однак для Ubuntu та багатьох систем на базі Debian це посилання /bin/dash. Усі оболонки, коли викликаються як sh, перейдуть в режим сумісності POSIX.

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

Примітка. Якщо bashвиклик в режимі POSIX, він все одно дозволить деякі речі [[, які не є POSIX, такі як масиви тощо. Ці речі можуть вийти з ладу в несистемі bash.


3
"на Ubuntu - це посилання на / bin / dash" та взагалі на інші системи на базі Debian. IIRC на FreeBSD / GhostBSD також є символьним посиланням /bin/ash.
Сергій Колодяжний

Щоб бути повністю портативним, поставте пробіл між шебангом та (абсолютним) контуром перекладача. Деякі системи шукають #! /замість просто #!.
Саймон Ріхтер

5
@SimonRichter Посилання на це було б приємно бачити.
Кусалаланда

@SergiyKolodyazhnyy Встановлена ​​версія sh на FreeBSD - це зола, а не символьна посилання.
Роб

2
@Kusalananda, гм, на цій сторінці йдеться про те, що це міф, тому його, мабуть, не враховують.
Саймон Ріхтер

12

Ви отримали це назад. /bin/shмайже ніколи не буває оболонкою Борна в наші дні, і саме тоді у вас виникають проблеми, коли ви використовуєте She #! /bin/sh-bang.

Оболонка Борна була оболонкою, написаною наприкінці 70-х років і замінила попередню оболонку Томпсона (також її називали sh). На початку 80-х Девід Корн написав кілька розширень для оболонки Борна, виправив декілька помилок та незручності дизайну (і представив деяких) і назвав його оболонкою Корна.

На початку 90-х POSIX вказав sh мову, засновану на підмножині оболонки Korn, і більшість систем тепер змінили їх /bin/shна або оболонку Korn, або на оболонку, відповідну цій специфікації. Що стосується BSD, вони поступово змінювали свої /bin/sh, спочатку (після того, як вони більше не могли використовувати оболонку Bourne з ліцензійних причин) оболонку Almquist, клон оболонки Bourne з деякими розширеннями ksh, тому вона стала сумісною з POSIX.

Сьогодні всі POSIX-системи мають оболонку, яку називають sh(найчастіше, але не обов'язково в /bin, POSIX не визначає шлях утиліт, які вона вказує), які, як правило, сумісні з POSIX. Він, як правило, заснований на ksh88, ksh93, pdksh, bash, ash або zsh², але не оболонці Bourne, оскільки оболонка Bourne ніколи не відповідала POSIX³. Деякі з цих оболонок ( bash, zsh, yashі деякі pdkshпохідні включити режим POSIX-сумісний при виклику , як shі в меншій мірі відповідає іншим чином ).

bash(відповідь GNU на оболонку Korn) насправді є єдиною оболонкою з відкритим кодом (і можна сказати, що підтримується лише зараз, оскільки інші, як правило, базуються на ksh88, який не отримав жодної нової функції з 90-х років), сертифікований як будучи сумісним з POSIX sh(як частина сертифікації macOS).

Коли ви пишете скрипт із #! /bin/sh -she-bang, ви повинні використовувати стандартний shсинтаксис (а також використовувати стандартний синтаксис для утиліт, що використовуються в цьому сценарії, якщо ви хочете бути портативними, це не тільки оболонка, яка бере участь при інтерпретації оболонки скрипт), то не має значення, яка реалізація цього стандартного shінтерпретатора синтаксису використовується ( ksh, bash...).

Не має значення, що ці оболонки мають розширення над стандартними, якщо ви не використовуєте їх. Це як для написання коду C, якщо ви пишете стандартний код C і не використовуєте розширення одного компілятора (наприклад gcc) або іншого, ваш код повинен складати ОК незалежно від реалізації компілятора, якщо компілятор сумісний.

Тут, з #! /bin/shвона Вибуху, ваша головна задача буде системи , де /bin/shє Bourne оболонки , яка, наприклад , не підтримує стандартні функції , такі як $((1+1)), $(cmd), ${var#pattern}... В цьому випадку вам може знадобитися обхідні як:

#! /bin/sh -
if false ^ true; then
  # in the Bourne shell, ^ is an alias for |, so false ^ true returns
  # true in the Bourne shell and the Bourne shell only.
  # Assume the system is Solaris 10 (older versions are no longer maintained)
  # You would need to adapt if you need to support some other system
  # where /bin/sh is the Bourne shell.
  # We also need to fix $PATH as the other utilities in /bin are
  # also ancient and not POSIX compatible.
  PATH=`/usr/xpg6/bin/getconf PATH`${PATH:+:}$PATH || exit
  export PATH
  exec /usr/xpg4/bin/sh "$0" "$@"
  # that should give us an environment that is mostly  compliant
  # to the Single UNIX Specification version 3 (POSIX.2004), the
  # latest supported by Solaris 10.
fi
# rest of the script

До речі, Ubuntu за замовчуванням /bin/shне є bash. Цього dashдня оболонка, що базується на NetBSD sh, сама на основі оболонки Almquist, яка здебільшого сумісна з POSIX, за винятком того, що вона не підтримує багатобайтові символи. На Ubuntu та інших системах, що базуються на Debian, ви можете вибирати між bashта dashза /bin/shдопомогою dpkg-reconfigure dash) 4 . shСценарії, що постачаються з Debian, повинні працювати однаково в обох оболонках, як вони написані стандарту політики Debian (набір стандарту POSIX). Ви, ймовірно, виявите, що вони також працюють добре в емуляції zsh' ( shабо, boshмабуть, ні, ksh93або в yashних немає localвбудованого (вимагається політикою Debian, але не POSIX)).

У всіх системах, що знаходяться в області Unix.stackexchange.com, є sh десь POSIX . Більшість з них мають /bin/sh(ви можете знайти дуже рідкісні, які не мають /binкаталогу, але ви, мабуть, не переймаєтесь цим), і це взагалі shінтерпретатор POSIX (а в рідкісних випадках - (нестандартна) оболонка Bourne ).

Але shце єдиний виконуваний інтерпретатор оболонки, який ви точно можете знайти в системі. Для інших оболонок ви можете бути впевнені, що матимуть дистрибутиви macOS, Cygwin та більшість GNU / Linux bash. Похідні від SYSV (Solaris, AIX ...) зазвичай мають ksh88, можливо ksh93. OpenBSD, MirOS матиме похідну pdksh. macOS матиме zsh. Але від цього жодної гарантії не буде. Ніякої гарантії того, bashчи буде встановлений будь-який з цих інших оболонок у /binбудь-якому іншому місці (як правило, він є /usr/local/binна BSD, коли він встановлений, наприклад). І звичайно ніякої гарантії версії оболонки, яка буде встановлена.

Зауважте, що #! /path/to/executableце не умова , це особливість усіх ядер, схожих на Unix ( впроваджені на початку 80-х років Денісом Річі ), що дозволяє виконувати довільні файли, вказуючи шлях інтерпретатора в першому рядку, починаючи з #!. Це може бути будь-який виконуваний файл.

При виконанні файлу, першої рядок починається з #! /some/file some-optional-arg, ядро закінчує виконання /some/fileз some-optional-arg, шляхом сценарію і вихідними аргументами в якості аргументів. Ви можете зробити цей перший рядок, #! /bin/echo testщоб побачити, що відбувається:

$ ./myscript foo
test ./myscript foo

Коли ви використовуєте /bin/sh -замість /bin/echo test, ядро ​​виконує /bin/sh - ./myscript foo, shінтерпретує код вмісту, який зберігається, myscriptі ігнорує цей перший рядок як коментар (починається з #).


¹ Напевно, єдина система, де сьогодні хтось із нас зіткнеться із системою /bin/sh, заснованою на оболонці Борна, - Solaris 10. Solaris - один з небагатьох Unice, який вирішив зберегти оболонку Bourne для зворотної сумісності ( shмова POSIX не повністю) назад сумісні з оболонкою Bourne і (принаймні для настільних і повних розгортань сервера) є POSIX в shінших місцях (в /usr/xpg4/bin/sh, заснованих на ksh88), але це змінилося в Solaris 11, де /bin/shзараз ksh93. Інші здебільшого є неіснуючими.

² Раніше /bin/shMacOS / X бувzsh , але згодом був змінений на bash. Це не zshосновний фокус, який слід використовувати як shреалізацію POSIX . Його shрежим полягає в першу чергу, щоб мати можливість вбудовувати або викликати ( source) shкод POSIX у zshсценарії

³ Нещодавно @schily розширив оболонку OpenSolaris (база на оболонці SVR4, заснована на оболонці Bourne), щоб стати сумісним POSIX, boshале я не знаю, що він ще використовується в будь-якій системі. Поряд з ksh88цим робить його другою сумісною з POSIX оболонкою на основі коду оболонки Bourne

4 У старих версіях ви також можете використовувати mkshабо більше lkshвтілення POSIX . Це оболонка MirOS (раніше MirBSD) на основі pdksh, сама заснована на оболонці Forsyth (чергове повторне втілення оболонки Борна))


Незначна річ (про код оболонки в середині відповіді): Чи не слід використовувати її відразу exec sh "$0" "$@"після встановлення PATH? Це shя міг би підібрати з потрібного місця, я б подумав.
Kusalananda

1
@Kusalananda, це має спрацювати, але є більш ризикованим, оскільки ми можемо опинитися у нескінченному циклі, якщо щось не так (наприклад, sh з неправильними дозволами, getconf змінено ...). У будь-якому разі, решта характерна для Solaris 10, тому ми також можемо жорстко кодувати все, включаючи вміст $PATH.
Стефан Шазелас

Будь-яке цитування для OSX, що використовує ksh як його оболонку POSIX. Його оболонка за замовчуванням раніше була tcsh, але я не пам'ятаю, щоб bash не використовувався особливо, оскільки Korn Shell не був відкритим кодом, поки не вийшов OSX
user151019

1
@ Марк, я не сказав, що OSX коли-небудь використовував ksh. Я сказав, що це було zsh, і вони перейшли на bash (спеціальний склад bash).
Стефан Шазелас

1
@fpmurphy, якщо поглянути на ранні версії, bash вже став на сторону ksh там, де ksh не був сумісний із оболонкою Bourne. У той час як вам довелося чекати, поки bash2 дістанеться до того ж рівня функції, що й ksh88, спочатку bash вже мав декілька розширень ksh, таких як $(...)режими emacs / vi, розширення tilde / brace (ті, які спочатку були з csh), fc, typeset, псевдонім , синтаксис функції ksh-style function ...
Stéphane Chazelas

8

Так, ви можете використовувати #!/bin/shв сценарії, оскільки /bin/shце (сподіваємось) передбачено в таких системах, як правило, через якесь посилання, яке змушує bashповодитися (більш-менш) як shби. Ось, наприклад, система Centos7, яка посилається shна bash:

-bash-4.2$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Dec  4 16:48 /bin/sh -> bash
-bash-4.2$ 

Ви також можете використовувати, #!/bin/bashякщо ви пишете bashсценарій тільки для цієї системи та хочете використовувати bashфункції. Однак такі сценарії страждатимуть від проблем переносу, наприклад, на OpenBSD, де bashвін встановлений лише в тому випадку, якщо адміністратор не вдається встановити його (я цього не роблю), а потім він встановлений /usr/local/bin/bash, а не /bin/bash. Суворо #!/bin/shсценарій POSIX повинен бути більш портативним.


Зверніть увагу на це: "Коли викликається як sh, Bash переходить у режим POSIX після зчитування файлів запуску." - gnu.org/software/bash/manual/bashref.html#Bash-POSIX-Mode
glenn jackman

2
Коли я пишу сценарії для серверів RHEL на своїй роботі, я використовую #!/bin/bashсаме так, щоб я міг скористатися функціями, які не є POSIX.
Monty Harder

@MontyHarder IIRC на RHEL - /bin/shце симпосилання на bash, це правильно? Я точно знаю, що в CentOS це, хоча.
Сергій Колодяжний

1
@SergiyKolodyazhnyy Так, на сервері RHEL я щойно перевірив, це символьне посилання на bash. Бінарний двір знає, яке ім'я було використано для його виклику, і коли воно називається, shвоно діє як старенька школа Борна sh.
Monty Harder

6

Ти запитав

чи правильно розміщувати коментар #! / bin / sh у скриптах оболонки, написаних у дистрибутивах ubuntu?

Відповідь залежить від того, що ви пишете в сценарії оболонки.

  • Якщо ви строго використовуєте портативні сценарії, сумісні з POSIX, і не використовуєте жодних команд bash, тоді ви можете використовувати /bin/sh.

  • Якщо ви знаєте, що сценарій ви використовуєте лише коли-небудь на машині з bash, і ви хочете використовувати специфічний для синтаксису bash, то вам слід використовувати/bin/bash

  • Якщо ви хочете бути впевнені, що сценарій працюватиме на асортименті машин Unix, тоді вам слід використовувати лише синтаксис, сумісний з POSIX, і/bin/sh

  • Якщо ви регулярно використовуєте іншу оболонку (наприклад , КШ , ЗШ або Tcsh ), і ви хочете використовувати цей синтаксис в скрипті, то ви повинні використовувати відповідний інтерпретатор (наприклад /bin/ksh93, /bin/zshчи /bin/tcsh)


3

Значок "#!" коментар не завжди використовується /bin/bashабо /bin/sh. Він просто перераховує те, що повинен бути перекладач, а не тільки для сценаріїв оболонок. Наприклад, зазвичай починаються мої сценарії python #!/usr/bin/env python.

Тепер різниця між #!/bin/shі #!/bin/bashполягає в тому, що /bin/shце не завжди є посиланням на /bin/bash. Часто, але не завжди. Тут є помітним винятком Ubuntu. Я бачив, що сценарії відмінно працюють на CentOS, але не в роботі Ubuntu, тому що автор використовував синтаксис bash для #!/bin/sh.


1

Вибачте, що налили холодну воду на всі ті чудові відповіді, які говорять про те, що /bin/shє у всіх системах Unix - вона присутня, за винятком найбільш використовуваної системи Unix усіх часів: Android.

У Android є своя оболонка /system/bin/sh, і зазвичай немає можливості встановити /bin/shпосилання навіть у кореневій системі (через те, як система блокується за допомогою використання selinux та можливостей (7) обмежувальних наборів).

Для тих, хто скаже, що андроїд не відповідає POSIX: також немає більшості дистрибутивів Linux та BSD. І існування /bin/shцього шляху не передбачено стандартом :

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


Хоча всі системи, які намагаються бути сумісними з POSIX, мають численні помилки відповідності (включаючи сертифіковані), Android (і більшість інших вбудованих систем, таких як ваш маршрутизатор або лампочка) не мають бути сумісними з POSIX. Android тут поза темою, за винятком випадків, коли мова йде про його інтерфейс POSIX.
Стефан Шазелас

@Christopher, який getconf? Наприклад, на Solaris 11.4, це був би той /usr/bin? Той, що відповідає /usr/xpg4/bin(на відповідність SUSv2), той у /usr/xpg6/bin(для відповідності SUSv3)? /usr/xpg7/bin(для SUSv4)?
Стефан Шазелас

@ StéphaneChazelas, якщо ми доходимо до судження про наміри, я думаю, що я можу легко відкопати деякі цитати Лінуса Торвальда або Тео де Раадта, так що вони не так переймаються POSIX ;-) І більшість вбудованих систем базуються на Linux + busbox, що навряд чи менш POSIX-сумісний, ніж типова система Unix-подібної. І а) андроїд насправді не є "вбудованою" системою; б) андроїдна система може бути зроблена сумісною з POSIX, не маючи оболонки в /bin/sh
mosvy

1
@mosvy, те, що ти кажеш, здебільшого вірно. Але Torvalds може говорити лише за ядро ​​Linux. Chet Ramey піклується про відповідність POSIX для bash, RedHat піклується про відповідність POSIX (вони спонсорують групу Austin та сидять на зустрічах своїх груп, вони підтримують багато програмного забезпечення GNU). Ідея полягає в тому, що POSIX - єдиний стандарт, на який дивляться більшість Unix-подібних систем. Користувачі дбають про сумісність з POSIX, оскільки це полегшує перенос програмного забезпечення в різні системи. Це не ідеально, але краще, ніж нічого. Android має власний API програмування, POSIX насправді не викликає особливих проблем.
Стефан Шазелас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.