Ich habe ein Projekt bestehend aus ca. 20 kleinen .sh
Dateien. Ich nenne diese "klein", weil im Allgemeinen keine Datei mehr als 20 Codezeilen enthält. Ich habe einen modularen Ansatz gewählt, da ich der Unix-Philosophie treu bin und es für mich einfacher ist, das Projekt zu pflegen.
Am Anfang jeder .sh
Datei stelle ich #!/bin/bash
.
Einfach ausgedrückt, ich verstehe, dass Skriptdeklarationen zwei Zwecke haben:
- Sie helfen dem Benutzer beim Abrufen, welche Shell zum Ausführen der Datei erforderlich ist (beispielsweise nach einigen Jahren ohne Verwendung der Datei).
- Sie stellen sicher, dass das Skript nur mit einer bestimmten Shell ausgeführt wird (in diesem Fall Bash), um ein unerwartetes Verhalten bei Verwendung einer anderen Shell zu verhindern.
Wenn ein Projekt von beispielsweise 5 Dateien auf 20 Dateien oder von 20 Dateien auf 50 Dateien wächst (nicht in diesem Fall, sondern nur zur Veranschaulichung), stehen 20 Zeilen oder 50 Zeilen Skriptdeklarationen zur Verfügung. Ich gebe zu, obwohl es für manche witzig sein mag, fühlt es sich für mich ein bisschen überflüssig an, 20 oder 50 zu verwenden und stattdessen nur 1 pro Projekt zu sagen (möglicherweise in der Hauptdatei des Projekts).
Gibt es eine Möglichkeit, diese angebliche Redundanz von 20 oder 50 oder einer viel größeren Anzahl von Zeilen von Skriptdeklarationen zu vermeiden, indem eine "globale" Skriptdeklaration in einer Hauptdatei verwendet wird?
quelle
/bin/bash -x "$script"
Antworten:
Obwohl Ihr Projekt jetzt möglicherweise nur aus 50 Bash-Skripten besteht, sammelt es früher oder später Skripten, die in anderen Sprachen wie Perl oder Python geschrieben wurden (für die Vorteile, die diese Skriptsprachen gegenüber Bash haben).
Ohne eine richtige
#!
Zeile in jedem Skript wäre es äußerst schwierig , die verschiedenen Skripte zu verwenden, ohne zu wissen, welcher Interpreter zu verwenden ist. Es spielt keine Rolle, ob jedes einzelne Skript von anderen Skripten ausgeführt wird , dies verschiebt nur die Schwierigkeit von den Endbenutzern zu den Entwicklern. Keine dieser beiden Personengruppen sollte wissen müssen, in welcher Sprache ein Skript geschrieben wurde, um es verwenden zu können.Shell-Skripte, die ohne
#!
-line und ohne expliziten Interpreter ausgeführt werden, werden auf unterschiedliche Weise ausgeführt, je nachdem, welche Shell sie aufruft (siehe z. B. die Frage, welcher Shell-Interpreter ein Skript ohne Shebang ausführt? Und insbesondere die Antwort von Stéphane ) in einer Produktionsumgebung (Sie möchten konsistentes Verhalten und möglicherweise sogar Portabilität).Skripte, die mit einem expliziten Interpreter ausgeführt werden, werden von diesem Interpreter ausgeführt, unabhängig davon, was in der
#!
-Zeile steht. Dies kann später zu Problemen führen, wenn Sie beispielsweise ein Bash-Skript in Python oder einer anderen Sprache erneut implementieren.Sie sollten diese zusätzlichen Tastenanschläge verwenden
#!
und jedem Skript eine -Zeile hinzufügen .In einigen Umgebungen gibt es in jedem Skript in jedem Projekt mehrteilige Gesetzestexte. Seien Sie sehr froh, dass es nur eine
#!
Zeile ist, die sich in Ihrem Projekt "überflüssig" anfühlt.quelle
#!
Zeile, sobald die Datei über eine ausführbare Berechtigung verfügt und nicht von einem Interpreter, sondern von der Shell geladen wird. Das heißt, es wird/path/to/myprog.pl
ein Perl-Programm ausgeführt, wenn die#!
Zeile vorhanden ist (auf den Perl-Interpreter zeigt) und die Datei über die Ausführungsberechtigung verfügt.Sie verstehen den Punkt falsch
#!
. Es ist eigentlich eine Anweisung an das Betriebssystem, dieses Programm unter dem definierten Interpreter auszuführen.Es könnte also ein Skript sein
#!/usr/bin/perl
und das resultierende Programm kann ausgeführt werden,./myprogram
und der Perl-Interpreter könnte verwendet werden. Ähnlich#!/usr/bin/python
würde ein Programm unter Python laufen.Die Zeile
#!/bin/bash
weist das Betriebssystem an, dieses Programm unter bash auszuführen.Hier ist ein Beispiel:
Also, obwohl meine Shell ksh ist, läuft das Programm "x" wegen der
#!
Zeile unter bash , und das können wir explizit in der Prozessauflistung sehen.quelle
ps -aux
kann eine Warnung geben,ps
gibt die WarnungWarning: bad syntax, perhaps a bogus '-'?
.ps
suooprts sowohl BSD- als auch UXIX- Argument-Syntax.-aux
ist falsch UNIX Stephen bedeutet wahrscheinlich,aux
die richtige BSD istps
den Aufruf anzeigtbash
) und nicht auf die explizite Syntax. (2)ps -aux
funktioniert einwandfrei unter CentOS 7 und Debian 9 ohne Warnungen; Diese Cut'n'Paste war genau die Ausgabe von meiner Maschine. Die ganze Diskussion, ob das-
benötigt wird oder nicht, gilt für ältere Versionen von Linux Procps, nicht für aktuelle Versionen.Auf
.sh
Was schlecht ist, ist das
.sh
am Ende des Dateinamens.Stellen Sie sich vor, Sie schreiben eines der Skripte in Python neu.
Nun muss man die erste Zeile ändern, das
#!/usr/bin/python3
ist nicht so schlimm, da man auch jede andere Codezeile in der Datei ändern musste. Sie müssen jedoch auch den Dateinamen vonprog.sh
in ändernprog.py
. Und dann müssen Sie überall in den anderen Skripten und all Ihren Benutzerskripten (die, von denen Sie nicht einmal wussten, dass sie existieren) suchen und sie ändern, um das neue Skript zu verwenden.sed -e 's/.sh/.py/g'
kann für diejenigen, die Sie kennen, helfen. Aber jetzt zeigt Ihr Revision Control Tool eine Änderung in vielen nicht verwandten Dateien.Alternativ machen Sie es auf Unix-Art und benennen das Programm
prog
nichtprog.sh
.Auf
#!
Wenn Sie die richtige haben
#!
, und legen Sie die Berechtigung / den Modus fest, um die Ausführung einzuschließen. Dann brauchen Sie den Dolmetscher nicht zu kennen. Der Computer erledigt das für Sie.Für Nicht-Gnu-Systeme lesen Sie das Handbuch für
chmod
(und lernen Sie Oktal), vielleicht lesen Sie es trotzdem.quelle
.image
für Bilder..audio
für Ton usw. Damit sagst du, worum es geht, aber nicht um die Implementierung / Codierung.launch-missiles
oderdelete-project-and-make-manager-pissed
ich nicht "nur ausführen" möchte, wenn ich nur neugierig auf die Sprache war :)file
Befehl. Es erkennt die meisten Dateitypen.Es ist wahrscheinlich erwähnenswert, dass dies völlig falsch ist. Die Hashbang-Zeile hindert Sie in keiner Weise daran, die Datei einem falschen Shell / Interpreter zuzuführen:
(oder ähnlich mit
awk -f array.sh
etc.)Ein anderer Ansatz zur Modularität wäre jedoch, Shell-Funktionen in den Dateien zu definieren, eine Funktion pro Datei und dann
source
die Dateien aus dem Hauptprogramm. Auf diese Weise würden Sie keine Hashbangs benötigen: Sie würden wie alle anderen Kommentare behandelt, und alles würde mit derselben Shell ausgeführt. Der Nachteil wäre, dass Siesource
die Dateien mit den Funktionen (z. B.for x in functions/*.src ; do source "$x" ; done
) benötigen und sie alle mit derselben Shell ausgeführt werden, sodass Sie eine davon nicht direkt durch eine Perl-Implementierung ersetzen können.quelle
Es gibt - es heißt Portabilität oder POSIX-Konformität. Bemühen Sie sich, Skripts immer portabel und shellneutral zu schreiben, und verwenden Sie nur Skripts, die
#!/bin/sh
Sie verwenden oder wenn Sie sie verwenden/bin/sh
interaktiv verwenden (oder zumindest aus einer POSIX-kompatiblen Shell wie z. B.ksh
).Portable Skripte schützen Sie jedoch nicht vor:
/bin/sh
Skripts mit auscsh
.Wenn ich meine Meinung äußern darf, ist "Vermeidung von Redundanzen" durch Eliminierung
#!
ein falsches Ziel. Das Ziel sollte sein , konsistente Leistung und tatsächlich ein funktionierendes Skript , das funktioniert, und hält Ecke Fällen folgt einige allgemeine Regeln , wie nicht-Parsing-ls oder immer-Zitat-Variablen-es sei denn-need-Wort-Splitting .Sie sind wirklich nicht für Benutzer - sie sind für das Betriebssystem, um den richtigen Interpreter auszuführen. "Richtig" bedeutet in diesem Fall, dass das Betriebssystem das findet, was in shebang enthalten ist. Wenn der Code darunter für eine falsche Shell steht - das ist die Schuld des Autors. Was den Benutzerspeicher angeht, glaube ich nicht, dass "Benutzer" von Programmen wie Microsoft Word oder Google Chrome jemals wissen müssen, in welcher Sprache Programme geschrieben sind. Autoren benötigen möglicherweise.
Andererseits müssen Sie sich bei portabel geschriebenen Skripten möglicherweise nicht mehr merken, welche Shell Sie ursprünglich verwendet haben, da portable Skripte in jeder POSIX-kompatiblen Shell funktionieren sollten.
Sie tun es nicht. Was unerwartetes Verhalten tatsächlich verhindert, ist das Schreiben portabler Skripte.
quelle
Der Grund, warum Sie
#!/bin/bash
jedes Skript oben einfügen müssen, ist, dass Sie es als separaten Prozess ausführen.Wenn Sie ein Skript als neuen Prozess ausführen, erkennt das Betriebssystem, dass es sich um eine Textdatei handelt (im Gegensatz zu einer ausführbaren Binärdatei), und es muss bekannt sein, welcher Interpreter ausgeführt werden soll. Wenn Sie es nicht mitteilen, kann das Betriebssystem nur anhand der Standardeinstellung raten (die ein Administrator ändern kann). Die
#!
Zeile (und natürlich das Hinzufügen von ausführbaren Berechtigungen) verwandelt eine einfache Textdatei in eine ausführbare Datei, die direkt ausgeführt werden kann, mit der Gewissheit, dass das Betriebssystem weiß, wie es damit umzugehen ist.Wenn Sie die
#!
Linie entfernen möchten , haben Sie folgende Optionen:Führen Sie das Skript direkt aus (so wie Sie es jetzt tun) und hoffen Sie, dass der Standardinterpreter mit dem Skript übereinstimmt - Sie sind wahrscheinlich auf den meisten Linux-Systemen sicher, aber nicht auf andere Systeme (z. B. Solaris) übertragbar, und es kann in geändert werden alles (ich könnte es sogar so einstellen, dass es in
vim
der Datei läuft !).Führen Sie das Skript mit aus
bash myscript.sh
. Dies funktioniert gut, aber Sie müssen den Pfad zum Skript angeben, und es ist chaotisch.Quell das Skript mit
. myscript.sh
, das das Skript innerhalb des aktuellen Interpreter-Prozesses ausführt (dh nicht als Unterprozess). Dies erfordert jedoch mit ziemlicher Sicherheit Änderungen an Ihren Skripten und macht sie weniger modular / wiederverwendbar.In den Fällen 2 und 3 benötigt die Datei keine Ausführungsberechtigungen (und sollte diese auch nicht haben), und es ist eine gute Idee , ihr ein
.sh
(oder.bash
) Suffix zu geben.Aber keine dieser Optionen passt zu Ihrem Projekt, da Sie sagten, Sie möchten Ihre Skripte modular halten (=> unabhängig und in sich geschlossen), also sollten Sie Ihre
#!/bin/bash
Zeile ganz oben in den Skripten belassen.In Ihrer Frage sagten Sie auch, dass Sie der Unix-Philosophie folgen. Wenn das stimmt, sollten Sie lernen, wofür die
#!
Zeile wirklich ist, und sie weiterhin in jedem ausführbaren Skript verwenden!quelle
then you should learn what the #! line is really for, and keep using it in every executable script!
. Man kann der U.Philosophie bis zu einem gewissen Punkt des Wissens folgen. Nach all diesen Antworten habe ich verstanden, warum es in diesen Begriff aufgenommen werden kann. Ich schlage vor, die Antwort zu bearbeiten und durch "Sehen Sie den Shebang als internen Teil der Unix-Philosophie, die Sie respektieren und übernehmen" zu ersetzen.