L'hai fatto al contrario. /bin/sh
non è quasi mai una shell Bourne in questi giorni, ed è quando è¹ che hai un problema quando usi un #! /bin/sh
bang 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/sh
con 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
, yash
e alcuni pdksh
derivati consentono una modalità POSIX-compliant Quando invocato come sh
e 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 sh
sintassi 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 sh
sintassi 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/sh
lei-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/sh
non è bash
di default. È in dash
questi 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 bash
e dash
per /bin/sh
con dpkg-reconfigure dash
) 4 . sh
gli 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 sh
di emulazione o bosh
(probabilmente non ksh93
né yash
che non hanno un local
builtin (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 /bin
directory ma probabilmente non ti interessa), e questo è generalmente un sh
interprete 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 bash
o più di queste shell vengano installate all'interno /bin
o altrove (di solito si trova /usr/local/bin
su BSD quando installato ad esempio). E ovviamente nessuna garanzia della versione della shell che verrà installata.
Si noti che #! /path/to/executable
non è 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/file
con some-optional-arg
, il percorso dello script e gli argomenti originali come argomenti. Puoi fare quella prima riga #! /bin/echo test
per 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
, sh
interpreta il codice contenuto archiviato myscript
e 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/sh
shell 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 sh
linguaggio POSIX non è completamente retrocompatibile con la shell Bourne) e (almeno per le distribuzioni desktop e full server) hanno POSIX sh
altrove (in /usr/xpg4/bin/sh
, basato su ksh88), ma questo è cambiato in Solaris 11 dove /bin/sh
ora è ksh93. Gli altri sono per lo più defunti.
² Lo era /bin/sh
di MacOS / Xzsh
, ma in seguito cambiò in bash
. L' zsh
obiettivo principale non è quello di essere utilizzato come sh
implementazione POSIX . La sua sh
modalità è principalmente quella di poter incorporare o chiamare ( source
) il sh
codice POSIX negli zsh
script
³ Di recente, @schily ha esteso la shell OpenSolaris (base sulla shell SVR4, basata sulla shell Bourne) per renderla conforme a POSIX, chiamata bosh
ma non sono ancora a conoscenza del fatto che sia utilizzata su qualsiasi sistema. Insieme a ksh88
ciò, la rende una seconda shell conforme a POSIX basata sul codice della shell Bourne
4 Nelle versioni precedenti, è possibile utilizzare anche la mksh
sua lksh
incarnazione POSIX . Questa è la shell MirOS (precedentemente MirBSD) basata su pdksh, essa stessa basata sulla shell Forsyth (un'altra reimplementazione della shell Bourne))