È corretto usare / bin / sh nell'hashbang se la shell Bourne non è disponibile in una distribuzione?


15

In generale, gli script di shell contengono il seguente commento alla prima riga del file script: #!/bin/sh. Secondo le ricerche che ho fatto, questo si chiama "hash bang" ed è un commento convenzionale. Questo commento informa Unix che questo file viene eseguito dalla Bourne Shell nella directory /bin.

La mia domanda inizia a quel punto. Fino ad ora non ho visto questo commento come #!/bin/bash. Lo è sempre #!/bin/sh. Tuttavia, le distribuzioni Ubuntu non hanno il programma Bourne Shell. Hanno il Bourne Again Shell (bash).

A quel punto, è corretto inserire il commento #!/bin/shnegli script di shell scritti nelle distribuzioni di Ubuntu?



1
Vedi la mia risposta a questa domanda serverfault: #! / Bin / sh vs #! / Bin / bash per la massima portabilità .
Gordon Davisson,

Più comunemente chiamatoshebang
fpmurphy

Risposte:


16

#!/bin/shdovrebbe funzionare su tutte le distribuzioni Unix e simili a Unix. È generalmente considerato l'hashtag più portatile, purché lo script sia conforme a POSIX. La /bin/shshell dovrebbe essere una shell che implementa lo standard di shell POSIX, indipendentemente da quale shell reale sia quella mascherata come /bin/shshell.


#!/bin/shè normalmente solo un collegamento ora poiché la shell Bourne non è più mantenuta. Su molti sistemi Unix /bin/shci sarà un collegamento /bin/ksho /bin/ash, su molti sistemi Linux basati su RHEL sarà un collegamento /bin/bash, tuttavia su Ubuntu e su molti sistemi basati su Debian è un collegamento /bin/dash. Tutte le shell, quando invocate come sh, entreranno in modalità compatibilità POSIX.

L'hashbang è un importante segnaposto perché consente una portabilità molto maggiore rispetto ad altri metodi, purché lo script sia rigorosamente conforme a POSIX (ripetuto per sottolineare l'importanza).

Nota: quando bashviene invocato in modalità POSIX, consentirà comunque alcune cose non POSIX come [[array, e altro. Quelle cose potrebbero fallire su un non bashsistema.


3
"su Ubuntu è un collegamento a / bin / dash" e in generale altri sistemi basati su Debian. IIRC su FreeBSD / GhostBSD è anche un collegamento simbolico a /bin/ash.
Sergiy Kolodyazhnyy,

Per essere completamente portatile, inserisci uno spazio tra lo shebang e il percorso (assoluto) dell'interprete. Alcuni sistemi cercano #! /invece che semplicemente #!.
Simon Richter,

5
@SimonRichter Un riferimento per questo sarebbe bello da vedere.
Kusalananda

@SergiyKolodyazhnyy La versione installata di sh su FreeBSD è ash e non un link simbolico.
Rob

2
@Kusalananda, hmm, questa pagina dice che questo è un mito, quindi probabilmente può essere ignorato.
Simon Richter,

12

L'hai fatto al contrario. /bin/shnon è quasi mai una shell Bourne in questi giorni, ed è quando è¹ che hai un problema quando usi un #! /bin/shbang bang.

La shell Bourne era una shell scritta alla fine degli anni '70 e sostituì la precedente shell Thompson (chiamata anche sh). All'inizio degli anni '80, David Korn scrisse alcune estensioni per la shell Bourne, sistemò alcuni bug e progettò goffaggine (e ne introdusse alcune) e la chiamò shell Korn.

All'inizio degli anni '90, POSIX ha specificato il sh linguaggio basato su un sottoinsieme della shell Korn e la maggior parte dei sistemi¹ ha ora cambiato la propria /bin/shcon la shell Korn o una shell conforme a tale specifica. Nel caso dei BSD, hanno gradualmente cambiato la loro /bin/sh, inizialmente (dopo che non potevano più usare la shell Bourne per motivi di licenza) la shell Almquist, un clone della shell Bourne con alcune estensioni ksh, quindi è diventata conforme a POSIX.

Oggi, tutti i sistemi POSIX hanno una shell chiamata sh(il più delle volte, ma non necessariamente in /bin, POSIX non specifica il percorso delle utility che specifica) che è per lo più conforme a POSIX. Si basa generalmente su ksh88, ksh93, pdksh, bash, ash o zsh², ma non sulla shell Bourne poiché la shell Bourne non è mai stata conforme a POSIX³. Alcuni di tali gusci ( bash, zsh, yashe alcuni pdkshderivati consentono una modalità POSIX-compliant Quando invocato come she sono meno compatibili altrimenti).

bash(la risposta GNU alla shell Korn) è in realtà l'unica shell open source (e si potrebbe dire solo attualmente mantenuta poiché le altre sono generalmente basate su ksh88 che non ha ottenuto alcuna nuova funzionalità dagli anni '90) che è stato certificato come essendo conforme a POSIX sh(come parte della certificazione macOS).

Quando scrivi uno script con un #! /bin/sh -she-bang, dovresti usare una shsintassi standard (e dovresti anche usare la sintassi standard per le utility usate in quello script se vuoi essere portatile, non è solo la shell che è coinvolta nell'interpretazione di una shell script), quindi non importa quale implementazione di quell'interprete di shsintassi standard viene utilizzata ( ksh, bash...).

Non importa che quelle shell abbiano estensioni oltre lo standard fintanto che non le usi. È come scrivere codice C, purché si scriva codice C standard e non si utilizzino le estensioni di un compilatore (come gcc) o dell'altro, il codice deve compilare OK indipendentemente dall'implementazione del compilatore, a condizione che il compilatore sia conforme.

Qui, con la vostra #! /bin/shlei-bang, il problema principale sarebbe i sistemi in cui /bin/shè la shell Bourne che, per esempio non supporta le funzionalità standard come $((1+1)), $(cmd), ${var#pattern}... Nel qual caso potrebbe essere necessario work-around come:

#! /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

A proposito, Ubuntu /bin/shnon è bashdi default. È in dashquesti giorni, una shell che si basa su NetBSD sh, a sua volta basata sulla shell Almquist che è per lo più conforme a POSIX tranne per il fatto che non supporta i caratteri multi-byte. Su Ubuntu e altri sistemi basati su Debian, puoi scegliere tra bashe dashper /bin/shcon dpkg-reconfigure dash) 4 . shgli script forniti con Debian dovrebbero funzionare allo stesso modo in entrambe le shell poiché sono scritti nello standard delle politiche Debian (un superset dello standard POSIX). Probabilmente troverete opera anche su OK nella zsh's shdi emulazione o bosh(probabilmente non ksh93yashche non hanno un localbuiltin (richiesto dalla politica Debian ma non POSIX)).

Tutti i sistemi nell'ambito di unix.stackexchange.com hanno un POSIX sh da qualche parte. La maggior parte di loro ha un /bin/sh(potresti trovare quelli molto rari che non hanno una /bindirectory ma probabilmente non ti interessa), e questo è generalmente un shinterprete POSIX (e in rari casi una shell Bourne (non standard) invece ).

Ma shè l'unico eseguibile dell'interprete della shell che puoi essere sicuro di trovare su un sistema. Per le altre shell, puoi essere sicuro che avranno macOS, Cygwin e la maggior parte delle distribuzioni GNU / Linux bash. I sistemi operativi derivati ​​da SYSV (Solaris, AIX ...) avranno generalmente ksh88, possibilmente ksh93. OpenBSD, MirOS avrà un derivato pdksh. macOS avrà zsh. Ma da ciò, non ci sarà alcuna garanzia. Nessuna garanzia sul fatto che una basho più di queste shell vengano installate all'interno /bino altrove (di solito si trova /usr/local/binsu BSD quando installato ad esempio). E ovviamente nessuna garanzia della versione della shell che verrà installata.

Si noti che #! /path/to/executablenon è una convenzione , è una caratteristica di tutti i kernel simili a Unix ( introdotti nei primi anni '80 da Dennis Ritchie ) che consente di eseguire file arbitrari specificando il percorso dell'interprete in una prima riga che inizia con #!. Può essere qualsiasi eseguibile.

Quando si esegue un file la cui prima riga inizia #! /some/file some-optional-arg, il kernel finisce /some/filecon some-optional-arg, il percorso dello script e gli argomenti originali come argomenti. Puoi fare quella prima riga #! /bin/echo testper vedere cosa sta succedendo:

$ ./myscript foo
test ./myscript foo

Quando si utilizza /bin/sh -invece di /bin/echo test, il kernel viene eseguito /bin/sh - ./myscript foo, shinterpreta il codice contenuto archiviato myscripte ignora quella prima riga in quanto è un commento (inizia con #).


¹ Probabilmente l'unico sistema oggi in cui qualcuno di noi si imbatterà in una /bin/shshell basata su Bourne è Solaris 10. Solaris è uno dei pochi Unice che ha deciso di mantenere lì una shell Bourne per compatibilità con le versioni precedenti (il shlinguaggio POSIX non è completamente retrocompatibile con la shell Bourne) e (almeno per le distribuzioni desktop e full server) hanno POSIX shaltrove (in /usr/xpg4/bin/sh, basato su ksh88), ma questo è cambiato in Solaris 11 dove /bin/shora è ksh93. Gli altri sono per lo più defunti.

² Lo era /bin/shdi MacOS / Xzsh , ma in seguito cambiò in bash. L' zshobiettivo principale non è quello di essere utilizzato come shimplementazione POSIX . La sua shmodalità è principalmente quella di poter incorporare o chiamare ( source) il shcodice POSIX negli zshscript

³ Di recente, @schily ha esteso la shell OpenSolaris (base sulla shell SVR4, basata sulla shell Bourne) per renderla conforme a POSIX, chiamata boshma non sono ancora a conoscenza del fatto che sia utilizzata su qualsiasi sistema. Insieme a ksh88ciò, la rende una seconda shell conforme a POSIX basata sul codice della shell Bourne

4 Nelle versioni precedenti, è possibile utilizzare anche la mkshsua lkshincarnazione POSIX . Questa è la shell MirOS (precedentemente MirBSD) basata su pdksh, essa stessa basata sulla shell Forsyth (un'altra reimplementazione della shell Bourne))


Cosa minore (circa la risposta intermedia del codice shell): non dovresti usare subito exec sh "$0" "$@"dopo aver impostato il PATH? Quello avrebbe dovuto shriprendere dal posto giusto, avrei pensato.
Kusalananda

1
@Kusalananda, dovrebbe funzionare ma è più rischioso in quanto potremmo finire in un ciclo infinito se qualcosa non va (come sh con permessi errati, getconf modificato ...). Comunque, il resto è specifico di Solaris 10, quindi potremmo anche hardcodificare tutto compreso il contenuto di $PATH.
Stéphane Chazelas,

Qualsiasi citazione per OSX usando ksh come shell POSIX. La sua shell predefinita era tcsh ma non ricordo che bash non venisse usato soprattutto perché Korn Shell non era open source fino a quando non uscì OSX
user151019

1
@Mark, non ho detto che OSX abbia mai usato ksh. Ho detto che era zsh e sono passati a bash (una build speciale di bash).
Stéphane Chazelas,

1
@fpmurphy, se guardi le prime versioni, bash si stava già schierando con ksh ovunque ksh non fosse compatibile con la shell Bourne. Mentre dovevi aspettare fino a bash2 per arrivare allo stesso livello di funzionalità di ksh88, bash inizialmente aveva già diverse estensioni di ksh come $(...), modalità emacs / vi, espansioni tilde / parentesi graffe (quelle inizialmente da csh), fc, typeset, alias , sintassi delle funzioni in stile ksh ...
Stéphane Chazelas,

8

Sì, è possibile utilizzare #!/bin/shin uno script perché /bin/sh(si spera) è previsto su tali sistemi, di solito tramite un collegamento di qualche tipo che fa bashcomportare (più o meno) come shfarebbe. Ecco un sistema Centos7, ad esempio, che collega sha bash:

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

È inoltre possibile utilizzare #!/bin/bashse si sta scrivendo uno bashscript solo per quel sistema e si desidera utilizzare le bashfunzionalità. Tuttavia, tali script soffriranno di problemi di portabilità, ad esempio su OpenBSD dove bashè installato solo se l'amministratore si prende la briga di installarlo (io no) e quindi è installato /usr/local/bin/bash, no /bin/bash. Uno #!/bin/shscript strettamente POSIX dovrebbe essere più portabile.


Nota questo: "Quando invocato come sh, Bash entra in modalità POSIX dopo aver letto i file di avvio." - gnu.org/software/bash/manual/bashref.html#Bash-POSIX-Mode
glenn jackman

2
Quando scrivo script per server RHEL nel mio lavoro, lo uso #!/bin/bashesattamente in modo da poter sfruttare le funzionalità non POSIX.
Monty Harder,

@MontyHarder IIRC su RHEL /bin/shè un link simbolico a bash, è corretto? Lo so per certo su CentOS, comunque.
Sergiy Kolodyazhnyy,

1
@SergiyKolodyazhnyy Sì, sul server RHEL che ho appena controllato, è un link simbolico a bash. Il binario sa quale nome è stato usato per invocarlo, e quando viene chiamato shsi comporta come Bourne vecchia scuola sh.
Monty Harder,

6

Hai chiesto

è corretto inserire il commento #! / bin / sh negli script della shell scritti nelle distribuzioni di Ubuntu?

La risposta dipende da cosa scrivi nello script della shell.

  • Se si utilizzano rigorosamente script compatibili POSIX portatili e non si utilizzano comandi specifici di bash, è possibile utilizzare /bin/sh.

  • Se sai che stai usando lo script solo su una macchina con bash e vuoi usare la sintassi specifica per bash, allora dovresti usare/bin/bash

  • Se vuoi essere sicuro che lo script funzionerà su un assortimento di macchine unix, allora dovresti usare solo la sintassi conforme a POSIX e/bin/sh

  • Se si utilizzano regolarmente un'altra shell (ad esempio ksh , zsh o tcsh ), e si desidera utilizzare la sintassi che nello script, allora si dovrebbe utilizzare l'interprete appropriato (come /bin/ksh93, /bin/zsho /bin/tcsh)


3

Il "#!" il commento non usa sempre/bin/bash o /bin/sh. Elenca semplicemente qualunque cosa dovrebbe essere l'interprete, non solo per gli script di shell. Ad esempio, i miei script Python di solito iniziano con #!/usr/bin/env python.

Ora la differenza tra #!/bin/she #!/bin/bashè che /bin/shnon è sempre un collegamento simbolico a /bin/bash. Spesso ma non sempre. Ubuntu è un'eccezione notevole qui. Ho visto degli script che funzionano bene su CentOS ma non funzionano su Ubuntu perché l'autore ha usato una sintassi specifica per bash #!/bin/sh.


1

Ci scusiamo per aver versato dell'acqua fredda su tutte quelle grandi risposte che dicono che /bin/shè presente in tutti sistemi Unix: è presente, tranne nel sistema Unix più usato di tutti i tempi: Android.

Android ha la sua shell dentro /system/bin/she di solito non c'è modo di creare un /bin/shcollegamento, anche su un sistema rooted (a causa del modo in cui il sistema è bloccato dall'uso di selinux e capacità (7) set di limiti).

Per coloro che diranno che Android non è conforme a POSIX: né lo sono la maggior parte delle distribuzioni Linux e BSD. E l'esistenza di /bin/shcon questo percorso non è obbligatoria per lo standard :

Le applicazioni devono tenere presente che lo standard PATHdella shell non può essere assunto come o /bin/sho /usr/bin/sh, e dovrebbe essere determinato dall'interrogazione del PATHreso getconf PATH, garantendo che il percorso restituito sia un percorso assoluto e non una shell incorporata.


Mentre tutti i sistemi che cercano di essere conformi a POSIX hanno numerosi bug di conformità (compresi quelli certificati), Android (e la maggior parte degli altri sistemi integrati come il router o il sistema operativo a lampadina) non intendono essere conformi a POSIX. Android è fuori tema qui tranne quando si tratta della sua interfaccia POSIX.
Stéphane Chazelas,

@Christopher, quale getconf? Ad esempio su Solaris 11.4, sarebbe quello in /usr/bin? Quello in /usr/xpg4/bin(per la conformità SUSv2), quello in /usr/xpg6/bin(per la conformità SUSv3)? /usr/xpg7/bin(per SUSv4)?
Stéphane Chazelas,

@ StéphaneChazelas se siamo in grado di giudicare le intenzioni, penso di poter facilmente estrarre alcune citazioni di Linus Torvalds o Theo de Raadt per l'effetto che a loro non importa così tanto di POSIX ;-) E la maggior parte dei sistemi embedded sono basati su Linux + busybox, che è quasi meno conforme a POSIX rispetto al tipico sistema simile a Unix. E a) Android non è in realtà un sistema "incorporato" eb) un sistema Android potrebbe essere compatibile con POSIX senza avere una shell in /bin/sh
mosvy

1
@mosvy, quello che dici è per lo più vero. Ma Torvalds può parlare solo per il kernel Linux. Chet Ramey si preoccupa della conformità POSIX per bash, RedHat si preoccupa della conformità POSIX (sponsorizzano il gruppo Austin e partecipano alle riunioni del gruppo, mantengono molto del software GNU). L'idea è che POSIX è l'unico standard a cui guardano la maggior parte dei sistemi simili a Unix. Gli utenti si preoccupano della conformità POSIX in quanto semplifica il trasferimento del software su sistemi diversi. Non è l'ideale ma è meglio di niente. Android ha una propria API di programmazione, POSIX non è davvero un problema.
Stéphane Chazelas,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.