Welchem ​​Zweck dient der eingebaute Doppelpunkt?

45

Ich habe viele Shell-Skripte gehackt, und manchmal verwirren mich die einfachsten Dinge. Heute bin ich auf ein Skript :gestoßen, das das (Doppelpunkt-) Bash-Builtin ausgiebig genutzt hat.

Die Dokumentation scheint einfach zu sein:

: (a colon)  
     : [arguments]  

Führen Sie nichts weiter aus, als Argumente zu erweitern und Umleitungen durchzuführen. Der Rückgabestatus ist Null.

Bisher habe ich dies jedoch nur bei Demonstrationen der Shell-Expansion gesehen. Der Anwendungsfall in dem Skript, auf das ich gestoßen bin, hat diese Struktur ausgiebig genutzt:

if [ -f ${file} ]; then
    grep some_string ${file} >> otherfile || :
    grep other_string ${file} >> otherfile || :
fi

Es gab tatsächlich Hunderte von Greps, aber sie sind nur mehr gleich. Außer der oben beschriebenen einfachen Struktur sind keine Eingabe- / Ausgabe-Umleitungen vorhanden. Später im Skript werden keine Rückgabewerte überprüft.

Ich lese dies als ein nutzloses Konstrukt, das sagt "oder nichts tun". Welchem ​​Zweck könnte es dienen, diese Greps mit "oder nichts tun" zu beenden? In welchem ​​Fall würde dieses Konstrukt ein anderes Ergebnis hervorrufen, als einfach das || :von allen Instanzen wegzulassen?

Caleb
quelle
10
Ein möglicher Zweck, den ich sehen kann, ist die Verwendung :als Alternative zu true. Vielleicht errexitist gesetzt und der Autor kümmert sich nicht um den Exit-Status einiger Befehle.
JW013
Die mit Stackoverflow verknüpfte Seite ist IMO etwas umfassender (also gut, um sowohl diese Seite als auch die verknüpfte Seite zu lesen).
Trevor Boyd Smith

Antworten:

29

Anscheinend werden die :s in Ihrem Skript anstelle von verwendet true. Wenn grepin der Datei keine Übereinstimmung gefunden wird, wird ein Exit-Code ungleich Null zurückgegeben. Wie jw013 in einem Kommentar erwähnt, errexitwird -edas Skript beendet, wenn grepeine Übereinstimmung nicht gefunden wird. Klar, das ist nicht das, was der Autor wollte, so (n) er hinzu || :den Exit - Status dieses bestimmten Verbindung Befehl immer Null, wie die häufiger (in meiner Erfahrung) zu machen || true/ || /bin/true.

Kevin
quelle
Duh. Dies war das Konzept eines RPM-Build-Skripts, und obwohl im Skript kein Exit-Code überprüft wurde, vergaß ich zu berücksichtigen, dass der übergeordnete Prozess möglicherweise überwacht.
Caleb
8
In diesem Fall würde ich von einer schlechten Skriptpraxis sprechen. Es ist funktional gleichbedeutend mit der Verwendung true, aber die semantische Absicht ist bei viel klarer true. :ist besser geeignet, wenn eine explizite NOP gewünscht wird.
JW013
Nach meiner Erfahrung ist dies in RPM-Skripten üblich. Es sollte wahrscheinlich nicht sein, aber da sind wir.
Mattdm
einig Puristen bevorzugen :statt , trueda :ist ein bashEinbau-wo , wie in trueder Regel eine kompilierte Binärdatei mit mehr Aufwand. Normalerweise benutze ich, trueweil der Code besser lesbar ist (ebenfalls bevorzuge ich die Verwendung sourcestatt .).
Trevor Boyd Smith
36

Das :Builtin ist auch bei der Shell-Erweiterung "Standardwerte zuweisen" von Nutzen, bei der die Erweiterung häufig nur für den Nebeneffekt verwendet wird und der erweiterte Wert weggeworfen wird:

# assign FOO=bar iff FOO is unset
: ${FOO:=bar}
Joni
quelle
2
Kam hier auf der Suche nach diesem, war verblüfft, als ich dieses Muster in einem Skript sah, um Standardwerte zu deklarieren.
ffledgling
21

Ich kann mir zwei Orte vorstellen, die ich :in der Vergangenheit benutzt habe.

while :
do
     shell commands
     some exit condition
done

Das ist eine Endlosschleife.

function doSomethingStub {
    :
}

Setzen Sie eine Stub-Funktion ein, um einen korrekten Kontrollfluss auf höchster Ebene zu erzielen.

Eine Verwendung, die ich früher gesehen habe: Statt einer #!/bin/sh(oder was auch immer) Linie würde man eine :Linie sehen. Einige der älteren Real Unix-Kernel oder Real Unix-Shells würden dies als "Ich bin ein Shell-Skript, lass mich laufen" bezeichnen. Wie ich mich erinnere, war dies gerade, als csh als gemeinsame interaktive Shell Einzug hielt.

Bruce Ediger
quelle
@BruceEdiger: Hast du einen Verweis auf die "shecolon" Linie?
l0b0
7
Endlich eine ": am Anfang eines Skripts" Referenz und Erklärung gefunden: faqs.org/faqs/unix-faq/faq/part3/section-16.html
Bruce Ediger
1
Das Verhalten am Anfang :ist sehr seltsam. Ich fand, dass es in der Tat dazu führt, dass das Skript mit ausgeführt wird sh. Wo wie beim Starten des Skripts ohne einen Schebang ... versucht es, das Skript mit der gerade ausgeführten Shell auszuführen (wenn Sie bashes also ausführen, versuchen Sie, es so auszuführen, als bashob Sie es hätten, cshdann versucht es, es so auszuführen csh).
Trevor Boyd Smith
19

Die :integrierte Version war bereits in der Thompson-Shell enthalten - sie wurde 1975 für Unix V6 dokumentiert . In der Thompson-Shell wurde eine Bezeichnung für den Befehl angegeben. Wenn Sie nie versucht haben, eine Zeile anzufangen, die mit "" beginnt , war diese Zeile praktisch ein Kommentar.:gotogoto

Die Bourne-Shell , der Vorfahr der Bourne / POSIX-Shells, wie wir sie kennen, hatte nie einen gotomir bekannten :Befehl , wurde jedoch als No-Op-Befehl beibehalten (dieser war bereits in Unix V7 vorhanden ).

Gilles 'SO - hör auf böse zu sein'
quelle
Punkt für informativen historischen Hintergrund.
Tony Barganski vor
12

Ich habe eine alte Referenz ausgegraben: "The UNIX Programming Environment" (c) 1984 von Kernighan und Pike.

Seite 147 (Shell Programming) sagt das:

":" ist ein in die Shell integrierter Befehl, der nur die Argumente auswertet und "true" zurückgibt. Stattdessen [unter Bezugnahme auf ein Skriptbeispiel] hätten wir true verwenden können , was lediglich einen echten Exit-Status zurückgibt. (Es gibt auch einen falschen Befehl.) ':' Ist jedoch effizienter als 'true', da es keinen Befehl aus dem Dateisystem ausführt . [Kursiv / Betonung gehört mir.]

fracjackmac
quelle
2
Natürlich trueist jetzt auf vielen Systemen auch eine Shell eingebaut.
Tripleee
8

Ich scheine mich zu erinnern, dass frühe Versionen der Shell keine Kommentarsyntax hatten. Eine Zeile beginnend mit :(die wahrscheinlich eine tatsächliche ausführbare Datei gewesen wäre, ähnlich wie /bin/true) wäre die beste Alternative gewesen.

Hier ist eine Manpage für die alte Thompson-Shell (keine Beziehung); Es wird keine Kommentarsyntax erwähnt.

Keith Thompson
quelle
4
Der Ursprung von :war in der Tat eine Bezeichnung für den gotoBefehl in einer alten Shell (ich weiß nicht, welche). Ein Label : somethingkönnte in der Tat als Kommentar verwendet werden, wenn es keine Übereinstimmung gibt goto. Die Praxis blieb auch nach dem gotoVerschwinden.
Gilles 'SO- hör auf böse zu sein'
8

":" ist praktisch zum Debuggen.

DEBUGLOG=": debugfunction"

statement
statement
$DEBUGLOG arg1 arg2 ...
statement
statement

Wenn die Debug-Funktion normal ausgeführt wird, wird sie nie ausgeführt. Gehen Sie also einfach über den Noop (Variablen und Platzhalter werden jedoch erweitert). Wenn ein ausführlicheres Debugging erforderlich ist, entfernen Sie das noop aus der Variablen, und die Debugfunktion wird mit den erforderlichen Argumenten aufgerufen.

Eine weitere nützliche Funktion ist der Blockkommentar, der in der Shell-Syntax fehlt.

: << COMMENT
all --statements --in --here
are now -a here document which are
passed to --the noop
COMMENT
Colin
quelle