Was ist der Zweck eines Befehls, der nichts tut, nur ein Kommentarführer ist, sondern tatsächlich eine in sich selbst eingebaute Shell ist?
Es ist langsamer als das Einfügen eines Kommentars in Ihre Skripte um etwa 40% pro Anruf, was wahrscheinlich stark von der Größe des Kommentars abhängt. Die einzigen möglichen Gründe, die ich dafür sehen kann, sind folgende:
# poor man's delay function
for ((x=0;x<100000;++x)) ; do : ; done
# inserting comments into string of commands
command ; command ; : we need a comment in here for some reason ; command
# an alias for `true' (lazy programming)
while : ; do command ; done
Ich denke, was ich wirklich suche, ist, welche historische Anwendung es gehabt haben könnte.
Antworten:
Historisch gesehen , haben Bourne - Shells nicht haben
true
undfalse
als integrierte Befehle.true
wurde stattdessen einfach auf:
undfalse
auf so etwas ausgerichtetlet 0
.:
ist etwas besser alstrue
für die Portabilität auf alte Muscheln aus Bourne. Betrachten Sie als einfaches Beispiel, dass Sie weder den!
Pipeline-Operator noch den||
Listen-Operator haben (wie dies bei einigen alten Bourne-Shells der Fall war). Damit bleibt dieelse
Klausel derif
Anweisung das einzige Mittel zur Verzweigung basierend auf dem Exit-Status:Da
if
eine nicht leerethen
Klausel erforderlich ist und Kommentare nicht als nicht leer gelten,:
dient sie als No-Op.Heutzutage (das heißt: in einem modernen Kontext) können Sie normalerweise entweder
:
oder verwendentrue
. Beide werden von POSIX spezifiziert und einige sindtrue
leichter zu lesen. Es gibt jedoch einen interessanten Unterschied: Es:
handelt sich um ein sogenanntes POSIX- Special , währendtrue
es sich um ein reguläres integriertes System handelt .In die Shell müssen spezielle Einbauten eingebaut werden. Regelmäßige Einbauten sind nur "normalerweise" eingebaut, aber es ist nicht streng garantiert. Normalerweise sollte es
:
auf dentrue
meisten Systemen kein reguläres Programm mit der Funktion in PATH geben.Der wahrscheinlich wichtigste Unterschied besteht darin, dass bei speziellen integrierten Funktionen jede von den integrierten Variablen festgelegte Variable - auch in der Umgebung während der einfachen Befehlsauswertung - nach Abschluss des Befehls bestehen bleibt, wie hier mit ksh93 gezeigt:
Beachten Sie, dass Zsh diese Anforderung ignoriert, ebenso wie GNU Bash, außer wenn es im POSIX-Kompatibilitätsmodus arbeitet. Alle anderen wichtigen "POSIX sh-abgeleiteten" Shells, einschließlich dash, ksh93 und mksh, beachten dies.
Ein weiterer Unterschied besteht darin, dass reguläre integrierte Funktionen kompatibel sein müssen
exec
- hier anhand von Bash demonstriert:POSIX weist auch ausdrücklich darauf hin, dass dies
:
möglicherweise schneller ist alstrue
, obwohl dies natürlich ein implementierungsspezifisches Detail ist.quelle
exec
?true
Recht damit, dass es sich um ein reguläres eingebautes Gerät handelt, aber er ist falsch darin, dassexec
er/bin/true
anstelle des eingebauten verwendet wird.: ${var?not initialized}
et al.:
ist eine spezielle integrierte Funktion und sollte keine von ihr benannte Funktion haben. Aber ist das nicht das am häufigsten gesehene Beispiel für die:(){ :|: & };:
Benennung einer Funktion mit Namen durch eine Gabelbombe:
?Ich benutze es, um Variablenbefehle einfach zu aktivieren / deaktivieren:
Somit
Dies sorgt für ein sauberes Skript. Dies ist mit '#' nicht möglich.
Ebenfalls,
ist eine der einfachsten Möglichkeiten, um sicherzustellen, dass 'afile' existiert, aber eine Länge von 0 hat.
quelle
>afile
ist noch einfacher und erzielt den gleichen Effekt.vecho=":"
? Nur zur besseren Lesbarkeit?Eine nützliche Anwendung für: ist, wenn Sie nur Parametererweiterungen für ihre Nebenwirkungen verwenden möchten, anstatt das Ergebnis tatsächlich an einen Befehl zu übergeben. In diesem Fall verwenden Sie das PE als Argument für entweder: oder false, je nachdem, ob Sie einen Exit-Status von 0 oder 1 wünschen
: "${var:=$1}"
. Ein Beispiel könnte sein . Da:
es ein eingebautes ist, sollte es ziemlich schnell sein.quelle
: $((a += 1))
(++
und--
Operatoren müssen nicht gemäß POSIX implementiert werden.) In bash, ksh und möglichen anderen Shells können Sie auch Folgendes tun:((a += 1))
oder((a++))
es wird jedoch nicht von POSIX angegeben.(())
wird jedoch als optionale Funktion angegeben. "Wenn eine Zeichenfolge, die mit" ((") beginnt, von der Shell als arithmetische Erweiterung analysiert wird, wenn ein '$' vorangestellt wird, können Shells, die eine Erweiterung implementieren, wobei" ((Ausdruck)) "als arithmetischer Ausdruck ausgewertet wird, behandelt werden das "((" als Einführung als arithmetische Auswertung anstelle eines Gruppierungsbefehls) ":
kann auch für Blockkommentare verwendet werden (ähnlich wie / * * / in C-Sprache). Wenn Sie beispielsweise einen Codeblock in Ihrem Skript überspringen möchten, können Sie Folgendes tun:quelle
\
jedes der Trennzeichen für den gleichen Effekt maskieren :: <<\SKIP
.Wenn Sie eine Datei auf null Byte kürzen möchten, was zum Löschen von Protokollen hilfreich ist, versuchen Sie Folgendes:
quelle
> file.log
ist einfacher und erzielt den gleichen Effekt.:>
ist tragbarer. Einige Shells (wie meinezsh
) instanziieren automatisch eine Katze in der aktuellen Shell und warten auf stdin, wenn eine Umleitung ohne Befehl erfolgt. Anstattcat /dev/null
,:
ist viel einfacher. Oft ist dieses Verhalten in interaktiven Shells anders als in Skripten. Wenn Sie das Skript jedoch so schreiben, dass es auch interaktiv funktioniert, ist das Debuggen durch Kopieren und Einfügen viel einfacher.: > file
sichtrue > file
(abgesehen von der Anzahl der Charaktere und dem glücklichen Gesicht) von einer modernen Hülle (vorausgesetzt:
undtrue
gleich schnell)?Es ist ähnlich wie
pass
in Python.Eine Verwendung wäre, eine Funktion zu stubben, bis sie geschrieben wird:
quelle
Zwei weitere Verwendungen, die in anderen Antworten nicht erwähnt werden:
Protokollierung
Nehmen Sie dieses Beispielskript:
In der ersten Zeile
set -x
druckt die Shell den Befehl aus, bevor sie ausgeführt wird. Es ist ein ziemlich nützliches Konstrukt. Der Nachteil ist, dass die üblicheecho Log message
Art der Anweisung die Nachricht jetzt zweimal druckt. Die Doppelpunktmethode umgeht das. Beachten Sie, dass Sie Sonderzeichen immer noch so entkommen müssen, wie Sie es möchtenecho
.Cron Berufsbezeichnungen
Ich habe gesehen, wie es in Cron-Jobs verwendet wird, wie folgt:
Dies ist ein Cron-Job, der das Skript
/opt/backup.sh
jeden Tag um 10:45 Uhr ausführt. Der Vorteil dieser Technik besteht darin, dass die E-Mail-Betreffs besser aussehen, wenn/opt/backup.sh
eine Ausgabe gedruckt wird.quelle
set -x
die ausgedruckten Befehle (einschließlich so etwas wie: foobar
) zu stderr.Sie können es in Verbindung mit backticks (
``
) verwenden, um einen Befehl auszuführen, ohne seine Ausgabe wie folgt anzuzeigen:Natürlich könnte man das auch tun
some_command > /dev/null
, aber die:
-Version ist etwas kürzer.Davon abgesehen würde ich nicht empfehlen, dies tatsächlich zu tun, da dies die Leute nur verwirren würde. Es kam mir nur als möglicher Anwendungsfall in den Sinn.
quelle
Es ist auch nützlich für polyglotte Programme:
Dies ist nun sowohl ein ausführbarer Shell-Skript und ein JavaScript - Programm: Sinn
./filename.js
,sh filename.js
undnode filename.js
alle arbeitet.(Auf jeden Fall ein bisschen seltsam, aber trotzdem effektiv.)
Einige Erklärungen, wie gewünscht:
Shell-Skripte werden zeilenweise ausgewertet; und der
exec
Befehl, wenn ausgeführt, beendet die Schale und ersetzt es den Prozeß mit dem resultierenden Befehl. Dies bedeutet, dass das Programm für die Shell folgendermaßen aussieht:Solange im Wort keine Parametererweiterung oder kein Aliasing auftritt, kann jedes Wort in einem Shell-Skript in Anführungszeichen gesetzt werden, ohne seine Bedeutung zu ändern. Dies bedeutet, dass dies
':'
äquivalent zu ist:
(wir haben es hier nur in Anführungszeichen gesetzt, um die unten beschriebene JavaScript-Semantik zu erreichen).... und wie oben beschrieben, ist der erste Befehl in der ersten Zeile ein No-Op (übersetzt
: //
oder, wenn Sie die Wörter lieber zitieren möchten)':' '//'
. Beachten Sie, dass der Befehl//
hier keine besondere Bedeutung hat, wie dies in JavaScript der Fall ist. Es ist nur ein bedeutungsloses Wort, das weggeworfen wird.)Schließlich ist der zweite Befehl in der ersten Zeile (nach dem Semikolon) das eigentliche Kernstück des Programms: Es ist der
exec
Aufruf, der das aufgerufene Shell-Skript durch einen Node.js-Prozess ersetzt, der aufgerufen wird, um den Rest des Skripts auszuwerten .In der Zwischenzeit wird die erste Zeile in JavaScript als Zeichenfolgenliteral (
':'
) und dann als Kommentar analysiert , der gelöscht wird. Für JavaScript sieht das Programm also folgendermaßen aus:Da sich das String-Literal in einer eigenen Zeile befindet, handelt es sich um eine No-Op-Anweisung und wird daher aus dem Programm entfernt. Das bedeutet, dass die gesamte Zeile entfernt wird und nur Ihr Programmcode (in diesem Beispiel der
function(){ ... }
Text) übrig bleibt .quelle
: //;
und~function(){}
tun? Vielen Dank:)
~function(){}
, das ist ein wenig komplizierter. Es gibt hier noch ein paar andere Antworten, die sich darauf beziehen, obwohl keine von ihnen es wirklich zu meiner Zufriedenheit erklärt. Wenn keine dieser Fragen es für Sie gut genug erklärt, können Sie es hier als Frage posten Gerne beantworte ich eine neue Frage ausführlich.node
. Der Funktionsteil dreht sich also nur um Javascript! Ich bin ok mit einem unären Operator vor IIFE. Ich dachte, das wäre in erster Linie auch Bash und habe die Bedeutung Ihres Beitrags nicht wirklich verstanden. Ich bin jetzt in Ordnung, danke für Ihre Zeit, die Sie damit verbracht haben, «Zusammenbruch» hinzuzufügen!~{ No problem. (= }
Selbstdokumentierende Funktionen
Sie können
:
die Dokumentation auch in eine Funktion einbetten.Angenommen, Sie haben ein Bibliotheksskript
mylib.sh
, das eine Vielzahl von Funktionen bietet. Sie können entweder die Bibliothek (. mylib.sh
) als Quelle verwenden und die Funktionen direkt danach aufrufen (lib_function1 arg1 arg2
) oder vermeiden, dass Ihr Namespace überfüllt ist, und die Bibliothek mit einem Funktionsargument (mylib.sh lib_function1 arg1 arg2
) aufrufen .Wäre es nicht schön, wenn Sie auch
mylib.sh --help
eine Liste der verfügbaren Funktionen und deren Verwendung eingeben und abrufen könnten, ohne die Funktionsliste im Hilfetext manuell pflegen zu müssen?Einige Kommentare zum Code:
declare -f
zählt alle verfügbaren Funktionen auf. Anschließend werden sie durch sed gefiltert, um nur Funktionen mit dem entsprechenden Präfix anzuzeigen.mylib.sh function1
und es wird intern in übersetztlib_function1
. Dies ist eine Übung, die dem Leser überlassen bleibt.$1
. Gleichzeitig wird Ihr Namespace unübersichtlich, wenn Sie die Bibliothek als Quelle verwenden. Wenn Ihnen das nicht gefällt, können Sie entweder den Namen in einen ähnlichen Namen ändernlib_help
oder die Argumente--help
im Hauptcode überprüfen und die Hilfefunktion manuell aufrufen.quelle
Ich habe diese Verwendung in einem Skript gesehen und dachte, es sei ein guter Ersatz für das Aufrufen des Basisnamens in einem Skript.
... dies ist ein Ersatz für den Code:
basetool=$(basename $0)
quelle
basetool=${0##*/}