Im Allgemeinen enthalten Shell - Skripten den folgenden Kommentar in der ersten Zeile der Skriptdatei: #!/bin/sh
. Nach meinen Recherchen wird dies als "Hash Bang" bezeichnet und ist ein herkömmlicher Kommentar. Dieser Kommentar informiert Unix darüber, dass diese Datei von der Bourne-Shell unter dem Verzeichnis ausgeführt wird /bin
.
Meine Frage beginnt in diesem Punkt. Bisher habe ich diesen Kommentar nicht gerne gesehen #!/bin/bash
. Es ist immer so #!/bin/sh
. Ubuntu-Distributionen verfügen jedoch nicht über das Bourne Shell-Programm. Sie haben die Bourne Again Shell (Bash).
Ist es in diesem Punkt richtig, den Kommentar #!/bin/sh
in Shell-Skripten zu platzieren, die in Ubuntu-Distributionen geschrieben wurden?
shebang
Antworten:
#!/bin/sh
sollte auf allen Unix- und Unix-ähnlichen Distributionen funktionieren. Es wird allgemein als das portabelste Hashbang angesehen, solange Ihr Skript POSIX-kompatibel ist. Die/bin/sh
Shell soll eine Shell sein, die den POSIX-Shell-Standard implementiert, unabhängig davon, was die eigentliche Shell ist, die sich als/bin/sh
Shell ausgibt.#!/bin/sh
ist normalerweise nur ein Link, da die Bourne-Shell nicht mehr gepflegt wird. Auf vielen Unix-Systemen/bin/sh
wird es eine Verknüpfung zu/bin/ksh
oder/bin/ash
auf vielen RHEL-basierten Linux-Systemen wird es eine Verknüpfung zu sein/bin/bash
, auf Ubuntu und vielen Debian-basierten Systemen ist es jedoch eine Verknüpfung zu/bin/dash
. Wenn alle Shells als aufgerufen werdensh
, wird der POSIX-Kompatibilitätsmodus aktiviert.Der Hashbang ist jedoch ein wichtiger Platzhalter, da er eine viel größere Portabilität als andere Methoden ermöglicht, sofern Ihr Skript ausschließlich POSIX-kompatibel ist (wiederholt, um die Wichtigkeit zu betonen).
Hinweis: Beim
bash
Aufrufen im POSIX-Modus sind weiterhin einige Nicht-POSIX-Elemente wie[[
Arrays und mehr zulässig. Diese Dinge können auf einem Nicht-bash
System fehlschlagen .quelle
/bin/ash
.#! /
statt nur#!
.Du hast es verkehrt herum.
/bin/sh
ist heutzutage fast nie mehr eine Bourne-Muschel, und es ist dann, wenn Sie ein Problem haben, wenn Sie einen She#! /bin/sh
-Bang verwenden.Die Bourne-Shell war eine Shell, die Ende der 70er Jahre geschrieben wurde und die vorherige Thompson-Shell (auch als "Shell" bezeichnet
sh
) ersetzte . In den frühen 80er Jahren hat David Korn einige Erweiterungen für die Bourne-Shell geschrieben, einige Fehler behoben und Ungeschicklichkeiten im Design behoben (und einige eingeführt) und sie als Korn-Shell bezeichnet.In den frühen 90er Jahren spezifizierte POSIX die
sh
Sprache basierend auf einer Teilmenge der Korn-Shell, und die meisten Systeme haben ihre Sprache jetzt/bin/sh
entweder in die Korn-Shell oder in eine Shell geändert , die dieser Spezifikation entspricht. Bei BSDs änderten sie schrittweise/bin/sh
die Almquist-Shell (nachdem sie die Bourne-Shell aus Lizenzgründen nicht mehr verwenden konnten), einen Klon der Bourne-Shell mit einigen ksh-Erweiterungen, sodass sie POSIX-kompatibel wurde.Heutzutage haben alle POSIX-Systeme eine Shell, die POSIX-kompatibel ist
sh
(meistens, aber nicht unbedingt/bin
, gibt POSIX nicht den Pfad der angegebenen Dienstprogramme an). Es basiert im Allgemeinen entweder auf ksh88, ksh93, pdksh, bash, ash oder zsh², jedoch nicht auf der Bourne-Shell, da die Bourne-Shell niemals POSIX-kompatibel war³. Ein paar dieser Schalen (bash
,zsh
,yash
und einigepdksh
Derivate ermöglichen eine POSIX-kompatiblen Modus , wenn aufgerufen , wiesh
und sind weniger konform auf andere Weise).bash
(die GNU-Antwort auf die Korn-Shell) ist tatsächlich die einzige Open-Source-Shell (und man könnte sagen, dass sie derzeit nur gewartet wird, da die anderen in der Regel auf ksh88 basieren, das seit den 90er Jahren keine neuen Funktionen mehr hat), die als zertifiziert wurde POSIX-konform seinsh
(im Rahmen der macOS-Zertifizierung).Wenn Sie ein Skript mit einem
#! /bin/sh -
She-Bang schreiben , sollten Sie eine Standardsyntax verwendensh
(und auch Standardsyntax für die in diesem Skript verwendeten Dienstprogramme verwenden, wenn Sie portabel sein möchten. Es ist nicht nur die Shell, die bei der Interpretation einer Shell beteiligt ist Skript), dann spielt es keine Rolle, welche Implementierung dieses Standard-sh
Syntax-Interpreters verwendet wird (ksh
,bash
...).Es spielt keine Rolle, dass diese Shells Erweiterungen über dem Standard haben, solange Sie sie nicht verwenden. Es ist wie beim Schreiben von C-Code. Solange Sie Standard-C-Code schreiben und keine Erweiterungen des einen
gcc
oder anderen Compilers verwenden , sollte der Code unabhängig von der Compilerimplementierung einwandfrei kompiliert werden, sofern der Compiler kompatibel ist.Hier mit dem
#! /bin/sh
sie Bang, Ihr Hauptproblem wäre die Systeme, in denen/bin/sh
ist die Bourne - Shell , dass zum Beispiel nicht unterstützt Standard - Features wie$((1+1))
,$(cmd)
,${var#pattern}
... , in dem Fall , dass Sie Umgehungen benötigen wie:Übrigens ist Ubuntu
/bin/sh
nichtbash
standardmäßig. Es istdash
heutzutage eine Shell, die auf NetBSD basiertsh
, selbst auf der Almquist-Shell, die größtenteils POSIX-kompatibel ist, außer dass sie keine Multi-Byte-Zeichen unterstützt. Auf Ubuntu und andere Debian-basierten Systemen können Sie wählen zwischenbash
unddash
für/bin/sh
mitdpkg-reconfigure dash
) 4 .sh
Mit Debian gelieferte Skripte sollten in beiden Shells genauso funktionieren, wie sie nach dem Debian-Richtlinienstandard (einer Obermenge des POSIX-Standards) geschrieben wurden. Sie werden wahrscheinlich feststellen, dass sie auch inzsh
dersh
Emulation funktionieren oderbosh
(wahrscheinlich nichtksh93
oderyash
nicht mitlocal
eingebautem Code (erforderlich für die Debian-Richtlinie, aber nicht für POSIX)).Alle Systeme im Geltungsbereich von unix.stackexchange.com haben
sh
irgendwo eine POSIX . Die meisten von ihnen haben eine/bin/sh
(Sie finden vielleicht sehr seltene, die kein/bin
Verzeichnis haben, aber das interessiert Sie wahrscheinlich nicht), und das ist im Allgemeinen ein POSIX-sh
Interpreter (und in seltenen Fällen eine (nicht standardmäßige) Bourne-Shell) ).Aber
sh
ist der einzige ausführbare Shell-Interpreter, den Sie auf einem System finden können? Für die anderen Shells können Sie sicher sein, dass macOS, Cygwin und die meisten GNU / Linux-Distributionen installiert sindbash
. Von SYSV abgeleitete Betriebssysteme (Solaris, AIX ...) haben im Allgemeinen ksh88, möglicherweise ksh93. OpenBSD, MirOS wird ein pdksh-Derivat haben. MacOS wird habenzsh
. Aber davon gibt es keine Garantie. Es kann weder garantiert werden, obbash
noch eine dieser anderen Shells in/bin
oder an einem anderen Ort installiert wird (dies ist beispielsweise bei/usr/local/bin
BSD-Installationen normalerweise der Fall). Und natürlich keine Garantie für die Version der Shell, die installiert wird.Beachten Sie, dass dies
#! /path/to/executable
keine Konvention ist , sondern eine Funktion aller Unix-ähnlichen Kernel ( eingeführt in den frühen 80ern von Dennis Ritchie ), mit der beliebige Dateien ausgeführt werden können, indem der Pfad des Interpreters in einer ersten Zeile beginnend mit angegeben wird#!
. Es kann sich um eine beliebige ausführbare Datei handeln.Wenn Sie eine Datei mit der ersten Zeile beginnt , deren ausführen
#! /some/file some-optional-arg
, beendet der Kernel - Ausführung nach oben/some/file
mitsome-optional-arg
, dem Pfad des Skripts und die ursprünglichen Argumente als Argumente. Sie können diese erste Zeile machen, um#! /bin/echo test
zu sehen, was passiert:Wenn Sie
/bin/sh -
anstelle von verwenden/bin/echo test
, wird der Kernel ausgeführt/bin/sh - ./myscript foo
,sh
der in gespeicherte Inhaltscode interpretiertmyscript
und die erste Zeile als Kommentar ignoriert (beginnt mit#
).¹ Wahrscheinlich
/bin/sh
ist Solaris 10 das einzige System, auf dem heutzutage jeder von uns auf ein System stößt, das auf der Bourne-Shell basiert. Solaris ist eines der wenigen Unices, die sich aus Gründen der Abwärtskompatibilität dafür entschieden haben, eine Bourne-Shell dort zu belassen (die POSIX-sh
Sprache ist nicht vollständig) Abwärtskompatibel mit der Bourne-Shell) und (zumindest für Desktop- und vollständige Server-Bereitstellungen) haben POSIX ansh
anderer Stelle (in/usr/xpg4/bin/sh
, basierend auf ksh88), aber das hat sich in Solaris 11 geändert, wo/bin/sh
jetzt ksh93 ist. Die anderen sind meistens verstorben.² Das
/bin/sh
von MacOS / X war früher,zsh
wurde aber später auf geändertbash
. Es ist nichtzsh
das Hauptaugenmerk, als POSIX-sh
Implementierung verwendet zu werden. Dersh
Modus besteht hauptsächlich darin,source
POSIX-sh
Code inzsh
Skripte einbetten oder aufrufen zu können³ Vor kurzem hat @schily die OpenSolaris-Shell (basierend auf der SVR4-Shell, basierend auf der Bourne-Shell) so erweitert, dass sie POSIX-kompatibel ist.
bosh
Mir ist jedoch noch nicht bekannt, dass sie auf einem beliebigen System verwendet wird. Zusammenksh88
damit ist es eine zweite POSIX-kompatible Shell, die auf dem Code der Bourne-Shell basiert4 In älteren Versionen können Sie auch
mksh
POSIX verwendenlksh
. Das ist die MirOS-Shell (ehemals MirBSD), die auf pdksh basiert, selbst basiert auf der Forsyth-Shell (eine weitere Neuimplementierung der Bourne-Shell).quelle
exec sh "$0" "$@"
nach dem Einstellen verwendenPATH
? Das solltesh
an der richtigen Stelle abgeholt werden, hätte ich gedacht.$PATH
.$(...)
z , ksh-style function syntax ...Ja, Sie können es
#!/bin/sh
in einem Skript verwenden, da/bin/sh
es (hoffentlich) auf solchen Systemen vorgesehen ist, normalerweise über einen Link, der dasbash
Verhalten (mehr oder weniger) wie ein normaler Link verhältsh
. Hier ist ein Centos7 System, zum Beispiel, dass Linkssh
zubash
:Sie können auch verwenden,
#!/bin/bash
wenn Sie einbash
Skript nur für dieses System schreiben und Funktionen verwenden möchtenbash
. Solche Skripte werden jedoch unter Portabilitätsproblemen leiden, zum Beispiel unter OpenBSD, wobash
nur installiert wird, wenn der Administrator sich die Mühe macht, es zu installieren (ich nicht) und es dann installiert wird/usr/local/bin/bash
, nicht/bin/bash
. Ein ausschließlich POSIX-#!/bin/sh
Skript sollte portabler sein.quelle
sh
wechselt Bash nach dem Lesen der Startdateien in den POSIX-Modus." - gnu.org/software/bash/manual/bashref.html#Bash-POSIX-Mode#!/bin/bash
genau diese, um die Vorteile von Nicht-POSIX-Funktionen nutzen zu können./bin/sh
ist ein Symlink zubash
, ist das richtig? Ich bin mir jedoch sicher, dass es CentOS ist.bash
. Die Binärdatei weiß, mit welchem Namen sie aufgerufen wurde, und wenn sie aufgerufen wird, verhält sie sichsh
wie Bourne der alten Schulesh
.Du hast gefragt
Die Antwort hängt davon ab, was Sie im Shell-Skript schreiben.
Wenn Sie ausschließlich portable POSIX-kompatible Skripte verwenden und keine bash-spezifischen Befehle verwenden, können Sie diese verwenden
/bin/sh
.Wenn Sie wissen, dass Sie das Skript immer nur auf einem Computer mit bash verwenden und die bash-spezifische Syntax verwenden möchten, sollten Sie verwenden
/bin/bash
Wenn Sie sicherstellen möchten, dass das Skript auf einer Reihe von Unix-Computern ausgeführt werden kann, sollten Sie nur POSIX-kompatible Syntax und verwenden
/bin/sh
Wenn Sie regelmäßig verwenden , eine andere Shell (zB ksh , zsh oder tcsh ), und dass die Syntax in Ihrem Skript verwenden möchten, dann Sie sollten den entsprechenden Interpreter (wie
/bin/ksh93
,/bin/zsh
, oder/bin/tcsh
)quelle
Das "#!" Kommentar verwendet nicht immer
/bin/bash
oder/bin/sh
. Es wird nur aufgeführt, was der Interpreter sein soll, nicht nur für Shell-Skripte. Zum Beispiel beginnen meine Python-Skripte normalerweise mit#!/usr/bin/env python
.Nun ist die Differenz zwischen
#!/bin/sh
und#!/bin/bash
ist , dass/bin/sh
nicht immer ein symbolischer Link zu/bin/bash
. Oft aber nicht immer. Ubuntu ist hier eine bemerkenswerte Ausnahme. Ich habe gesehen, dass Skripte unter CentOS einwandfrei funktionieren, unter Ubuntu jedoch nicht, weil der Autor die bash-spezifische Syntax mit verwendet hat#!/bin/sh
.quelle
Es tut mir leid, dass Sie all diese tollen Antworten mit kaltem Wasser übergossen haben, die besagen, dass
/bin/sh
sie in allen Unix-Systemen vorhanden sind - es sei denn, es handelt sich um das am häufigsten verwendete Unix-System aller Zeiten: Android.Android hat seine Shell
/system/bin/sh
und es gibt normalerweise keine Möglichkeit, eine/bin/sh
Verknüpfung herzustellen , auch nicht auf einem verwurzelten System (aufgrund der Art und Weise, wie das System durch die Verwendung von Selinux und Capabilities (7) -Bounding-Sets gesperrt wird).Für diejenigen, die sagen werden, dass Android nicht POSIX-konform ist, ebenso wenig wie die meisten Linux- und BSD-Distributionen. Und die Existenz von
/bin/sh
mit diesem Weg ist nicht durch die Norm vorgeschrieben :quelle
getconf
? Wäre dies beispielsweise unter Solaris 11.4 der Fall/usr/bin
? Der in/usr/xpg4/bin
(für SUSv2-Konformität), der in/usr/xpg6/bin
(für SUSv3-Konformität)?/usr/xpg7/bin
(für SUSv4)?/bin/sh