Shell-Skript-Header (#! / bin / sh vs #! / bin / csh)

88

Warum beginnen alle Skriptdateien mit?

#!/bin/sh

oder mit

#!/bin/csh

Ist das erforderlich? Was ist der Zweck davon? Und was ist der Unterschied zwischen den beiden?

Eins zwei drei
quelle
1
Für ein csh-Skript sollten Sie verwenden #!/bin/csh -f; Das -fweist die Shell an, das .loginund nicht des Benutzers zu verwenden .cshrc, wodurch das Skript schneller ausgeführt wird und Abhängigkeiten vom Setup des Benutzers vermieden werden. (Oder noch besser, schreiben Sie keine csh-Skripte.) Verwenden Sie sie nicht -ffür sh- oder bash-Skripte. es hat nicht die gleiche Bedeutung.
Keith Thompson

Antworten:

96

Dies ist bekannt als Shebang:

http://en.wikipedia.org/wiki/Shebang_(Unix)

#! Interpreter [optional-arg]

Ein Shebang ist nur relevant, wenn ein Skript über die Ausführungsberechtigung verfügt (z. B. chmod u + x script.sh).

Wenn eine Shell das Skript ausführt, wird der angegebene Interpreter verwendet.

Beispiel:

#!/bin/bash
# file: foo.sh
echo 1

$ chmod u+x foo.sh
$ ./foo.sh
  1
Kwarrick
quelle
@Kolob Canyon brauchen Sie nicht, aber es kann einigen Editoren bei der Hervorhebung der Syntax helfen (obwohl es normalerweise andere Möglichkeiten gibt, dasselbe zu erreichen): unix.stackexchange.com/a/88730/193985
Braham Snyder
40

Die #!Zeile teilt dem Kernel (insbesondere der Implementierung des execveSystemaufrufs) mit, dass dieses Programm in einer interpretierten Sprache geschrieben ist. Der folgende absolute Pfadname identifiziert den Interpreter. Zu Maschinencode kompilierte Programme beginnen mit einer anderen Bytesequenz - auf den meisten modernen Unixen 7f 45 4c 46( ^?ELF), die sie als solche identifiziert.

Sie können jedem Programm nach dem einen absoluten Pfad zuweisen#! , solange dieses Programm selbst kein #!Skript ist. Der Kernel schreibt einen Aufruf von neu

./script arg1 arg2 arg3 ...

wo ./scriptfängt zum Beispiel an, #! /usr/bin/perlals ob die Kommandozeile tatsächlich gewesen wäre

/usr/bin/perl ./script arg1 arg2 arg3

Wie Sie gesehen haben, können Sie #! /bin/shauch ein Skript schreiben, das von interpretiert werden soll sh.

Die #!Zeile wird nur verarbeitet, wenn Sie das Skript direkt aufrufen ( ./scriptin der Befehlszeile). Die Datei muss auch ausführbar sein ( chmod +x script). Wenn Sie dies tun, ist sh ./scriptdie #!Zeile nicht erforderlich (und wird ignoriert, falls vorhanden), und die Datei muss nicht ausführbar sein. Der Punkt des Merkmals ist die direkte Eingabe zu ermöglichen invoke interpretiert sprachige Programme , ohne zu wissen , welche Sprache sie geschrieben werden. (Do grep '^#!' /usr/bin/*- Sie werden feststellen , dass es sehr viele Aktienprogramme in der Tat die Verwendung dieser Funktion.)

Hier sind einige Regeln für die Verwendung dieser Funktion:

  • Das #!müssen die ersten zwei Bytes in der Datei sein. Insbesondere muss die Datei in einer ASCII-kompatiblen Codierung vorliegen (z. B. UTF-8 funktioniert, UTF-16 jedoch nicht) und darf nicht mit einer "Byte-Ordnungsmarke" beginnen, da der Kernel sie sonst nicht als erkennt #!Skript.
  • Der Pfad danach #!muss ein absoluter Pfad sein (beginnt mit /). Es darf keine Leerzeichen, Tabulatoren oder Zeilenumbrüche enthalten.
  • Es ist ein guter Stil, aber nicht erforderlich, ein Leerzeichen zwischen dem #!und dem zu setzen /. Stellen Sie dort nicht mehr als ein Leerzeichen ein.
  • Sie können keine Shell-Variablen in die #!Zeile einfügen, sie werden nicht erweitert.
  • Sie können ein Befehlszeilenargument nach dem absoluten Pfad einfügen, das durch ein einzelnes Leerzeichen von diesem getrennt ist. Wie der absolute Pfad darf dieses Argument keine Leerzeichen, Tabulatoren oder Zeilenumbrüche enthalten. Manchmal ist dies notwendig, um Dinge zum Laufen zu bringen ( #! /usr/bin/awk -f), manchmal ist es nur nützlich ( #! /usr/bin/perl -Tw). Leider können Sie nicht zwei oder mehr Argumente nach dem absoluten Pfad setzen.
  • Einige Leute werden Ihnen sagen , zu verwenden , #! /usr/bin/env interpreterstatt #! /absolute/path/to/interpreter. Dies ist fast immer ein Fehler. Dadurch hängt das Verhalten Ihres Programms von der $PATHVariablen des Benutzers ab, der das Skript aufruft. Und nicht alle Systeme haben envin erster Linie.
  • Programme, die setuidoder setgidBerechtigungen benötigen, können nicht verwendet werden #!. Sie müssen zu Maschinencode kompiliert werden. (Wenn Sie nicht wissen, was setuidist, machen Sie sich darüber keine Sorgen.)

In Bezug cshdarauf bezieht es sich in shetwa wie Nutrimat Advanced Tea Substitute auf Tee. Es hat (oder hatte eher; moderne Implementierungen shhaben aufgeholt) eine Reihe von Vorteilen gegenüber der shinteraktiven Nutzung, aber die Verwendung (oder dessen Nachkommen tcsh) für die Skripterstellung ist fast immer ein Fehler . Wenn Sie mit Shell-Skripten im Allgemeinen noch nicht vertraut sind, empfehle ich Ihnen dringend, sie zu ignorieren und sich darauf zu konzentrieren sh. Wenn Sie einen cshVerwandten als Anmeldeshell verwenden, wechseln Sie zu bashoder zsh, damit die interaktive Befehlssprache mit der Skriptsprache übereinstimmt, die Sie lernen.

zwol
quelle
In neueren Linux-Versionen kann der angegebene Interpreter ein Skript sein. Es ist üblich, das Leerzeichen nach dem wegzulassen #!. Kein Kommentar dazu, ob das ein guter Stil ist. In dieser Frage und meiner Antwort finden Sie eine Diskussion über die Vor- und Nachteile des #!/usr/bin/envHacks.
Keith Thompson
@KeithThompson Ich habe den Eindruck, dass Linux die einzige gängige Unix-Variante ist, mit der der Interpreter ein Skript sein kann, sodass man sich immer noch nicht darauf verlassen kann. Seit ich das geschrieben habe, bin ich selbst auf eine Situation gestoßen, in #!/usr/bin/envder das Richtige war, aber ich bin weiterhin der Meinung, dass es fast immer eine schlechte Idee ist.
zwol
4

Dies definiert, welche Shell (Befehlsinterpreter) Sie zum Interpretieren / Ausführen Ihres Skripts verwenden. Jede Shell unterscheidet sich geringfügig in der Art und Weise, wie sie mit dem Benutzer interagiert und Skripte (Programme) ausführt.

Wenn Sie an der Unix-Eingabeaufforderung einen Befehl eingeben, interagieren Sie mit der Shell.

#!/bin/cshBezieht sich zB auf die C-Shell, /bin/tcshdie T-Shell, /bin/bashdie Bash-Shell usw.

Sie können erkennen, welche interaktive Shell Sie verwenden

 echo $SHELL

Befehl oder alternativ

 env | grep -i shell

Sie können Ihre Befehlsshell mit dem chshBefehl ändern .

Jedes hat einen etwas anderen Befehlssatz und eine andere Art der Zuweisung von Variablen sowie einen eigenen Satz von Programmierkonstrukten. Zum Beispiel sieht die if-else-Anweisung mit bash anders aus als die in der C-Shell.

Diese Seite könnte von Interesse sein, da sie zwischen bash- und tcsh-Befehlen / -Syntax "übersetzt".

Mit der Direktive im Shell-Skript können Sie Programme mit einer anderen Shell ausführen. Zum Beispiel benutze ich die tcshShell interaktiv, führe aber häufig Bash-Skripte mit / bin / bash in der Skriptdatei aus.

Beiseite:

Dieses Konzept erstreckt sich auch auf andere Skripte. Wenn Sie beispielsweise in Python programmieren, würden Sie setzen

 #!/usr/bin/python

oben in Ihrem Python-Programm

Levon
quelle
Also ist es erforderlich? Woher weiß ich, welche Shell ich wirklich benutze?
Eins Zwei Drei
Wenn ich also die Skripte schreibe, die jemand auf seinem Computer verwenden soll, und ich nicht weiß, welche Shell er verwendet. (Diese Person hat leider keine Ahnung von diesem Zeug, daher kann sie nur das Skript ausführen, ohne etwas zu ändern). Kann ich so etwas machen #! $SHELL? Würde dies die richtige Hülle in den Shebang bringen?
Eins Zwei Drei
1
@OneTwoThree Die meisten Systeme haben die Standard-Shells. Wenn Sie ein Bash- oder Csh-Skript schreiben, sind Sie in Ordnung. Welche Shell sie interaktiv verwenden, spielt keine Rolle, das ist das Schöne an der zB !#/bin/bashRichtlinie. Es teilt dem System mit, welche Shell zum Ausführen Ihres Shell-Skripts verwendet werden soll.
Levon
Der Wert von $SHELLsagt Ihnen nicht unbedingt, welche Shell Sie gerade ausführen. Normalerweise wird Ihnen Ihre Standard- Shell angezeigt . tcsh setzt $versionund $tcsh; Bash-Sets $BASH_VERSION. Nicht alle Schalen haben notwendigerweise ähnliche Mechanismen.
Keith Thompson
1
@OneTwoThree: Die #!Zeile muss mit der Syntax des Skripts übereinstimmen, nicht mit der interaktiven Shell, die von demjenigen verwendet wird, der das Skript ausführt .
Keith Thompson