Was bedeutet dieses seltsame Symbol ":>" in der Bash?

47

Ich habe etwas in einem Drehbuch gefunden, das aber nicht zum Hauptskript gehört. Es war :>in einer Linie.

Können Sie mir erklären, was das bedeutet?

:> file
while read A B C D E; do echo "$A;$B;$D;$E;$C" >> file; done < otherfile
diego9403
quelle
6
Wichtig ist, dass :>es sich nicht um einen einzelnen Bediener handelt. Es ist möglicherweise einfacher zu verstehen, wenn Sie es : > filestattdessen als lesen .
jpfx1342
Es bedeutet , dass die Person , die das Skript zu schreiben , sollte die Ausgabe der Schleife in die Datei umgeleitet hat: while read A B C D E; do echo "$A;$B;$D;$E;$C"; done < otherfile > file. Oder noch besser, sie hätten das richtige Werkzeug für den Job verwenden sollen, awk, wie von Peter vorgeschlagen . Abgesehen davon möchten Sie den -rSchalter fast immer mit verwendenread .
Tom Fenech
Außerhalb der Bash wäre es ein Smiley für eine Krähe.
smci

Antworten:

46

Es gab:> in einer Zeile eines Bash-Skripts. Was heißt das?

:> file

Es ist eine Abkürzung, um zu sagen:

  • Wenn filees nicht existiert, dann erstelle es, andernfalls schneide es auf 0Bytes ab.

Das bedeutet, Sie können sicher sein, dass es fileexistiert und es leer ist.

Sie können auch verwenden > file, :> fileist aber tragbarer.

Siehe die Stapelüberlauf-Frage Was ist der Zweck des ':' (Doppelpunkt) GNU Bash Builtin? für mehr Informationen.

DavidPostill
quelle
Ich verstehe die zweite Zeile nicht. Ich dachte, dass read Variablen liest. Befehlsecho ist auch seltsam. Könntest du erklären?
diego9403
Ich bin kein Unix-Experte, aber ich denke, die zweite Zeile liest Dinge aus otherfileund gibt echosie aus file. Es macht auch Variablen aus dem, was es liest ... Wenn Sie eine eindeutige Antwort wünschen, stellen Sie bitte Ihre eigene Frage.
DavidPostill
2
@ diego9403: Ruft eine readEingabe von stdin ab. Allein würde es lesen, was Sie eingeben. Da stdin weitergeleitet wurde, <otherfilewird der Inhalt von otherfilein stdin "getippt". So werden readdie Werte zeilenweise in die Variablen $ A, $ B, $ C, $ D und $ E geschrieben.
Slebetman
Es ist also nur eine obskurere Alternative zu truncateCoreutils?
Federico Poloni
1
@PeterCordes Ich meinte nicht "obskur" wie in "es ist ungewöhnlich", aber wie in "es ist weniger klar für den Leser".
Federico Poloni
29

Es sieht aus wie eine ausgefallene Art, eine neue Datei zu erstellen. In bash :ist ein Null-Befehl:

$ type : 
: is a shell builtin 
$ help : 
:: :
    Null command.

    No effect; the command does nothing.

    Exit Status:
    Always succeeds.

>Leitet die Ausgabe :in eine Datei um.

Arkadiusz Drabczyk
quelle
2
Die Datei wird auch abgeschnitten, wenn sie bereits vorhanden ist ...
DavidPostill
2
ja, das ist , was >tut
Arkadiusz Drabczyk
2
:ist eine Abkürzung für true. Möglicherweise in einigen Muscheln, trueist ein eingebautes nicht? Beide sind in bash integriert.
Peter Cordes
12

:ist ein anderer Name für true. Beide sind Shell-Builtins in Bash, aber es gibt keine /bin/:, nur eine /bin/true. Die Ausgabeumleitung bewirkt, dass die Shell open(2)die Datei mit O_CREAT|O_TRUNC. Wenn nichts geschrieben ist, bleibt die Länge Null.

Das Zusammenfügen dieser beiden Teile :> fileist eine gängige Redewendung für das Abschneiden von Dateien. Die meisten Leute würden versuchen, es durch Schreiben weniger komisch aussehen zu lassen : >file.


Da Sie in einem Kommentar zur 2. Zeile gefragt haben, werde ich meine Kommentare in eine Antwort umwandeln. (Auch wenn Sie dies nicht in Ihrer Frage gestellt haben.)

Die 2. Zeile ist eine Schleife, die Zeilen otherfilein einige benannte Variablen einliest . Der Schleifenkörper echodruckt sie mit ;Trennzeichen anstelle der zuvor verwendeten Leerzeichen. filewird bei jeder Iteration geschlossen und erneut geöffnet (zum Anhängen), da sich die Umleitung innerhalb der Schleife befindet. Die Verwendung von while ...;do read -r ...;done <otherfile >filewürde weniger lästig sein, und Sie müssen die Datei nicht erst abschneiden. read -risst nicht \als Fluchtcharakter.

Die Textverarbeitung in Bash ist ziemlich langsam. Ein Teil davon ist unvermeidlich: Es readmuss jeweils ein Byte (ein read(2)Systemaufruf pro Byte) gesendet werden, um ein Überschießen des Zeilenendes zu vermeiden. Es wäre besser, das richtige Werkzeug für den Job zu verwenden:

awk -vOFS=';' '{ print $1, $2, $4, $5, $3 }' -- otherfile  >file

--bedeutet, dass Ihr Skript nicht kaputt geht, wenn der otherfileName "albern" lautet --version.

Wenn Sie das Ausgabefeldtrennzeichen auf festlegen, ;können Sie nur mehrere Felder als Argumente zum Drucken übergeben. Shell readweist der letzten Variablen den gesamten Rest der Zeile mit Leerzeichen zu, aber es gibt keine Möglichkeit, awk anzuweisen, nur in 5 aufzuteilen. Perl macht dies einfach, da splites ein Maximum an Feldern haben kann, aber es ist viel langsamer zu starten als awk.

Eigentlich stellte sich heraus, dass es nicht so schwer war, nur einen hässlichen Regex zu schreiben. $5Wenn Sie nicht in awk, sondern in Rest-of-the-Line arbeiten möchten, verlieren Sie beim Überlaufen von Feldern immer noch das ursprüngliche Leerzeichen. Meine erste tragfähige Idee ist , zu verwenden , gensubauf $0(die ganze Zeile) die ersten 4 Felder (dh nicht-Raum , gefolgt von Raum) zu entfernen, so dass alles anderes:

awk -vOFS=';' '{ tail = gensub("[[:space:]]*([^[:space:]]+[[:space:]]+){4}", "", 1); print $1, $2, $4, tail, $3 }' -- otherfile >file

Ich habe es gleich beim ersten Versuch richtig verstanden, aber die Tatsache, dass ich davon beeindruckt war, sagt etwas über die Lesbarkeit dieses awk-Codes aus. >. <

Beachten Sie, wie es das gleiche ist printwie zuvor, aber mit tailanstelle von $5.

echo 'A  B c DD    e      f g    f' | 
  awk -vOFS=\; '{ tail = gensub("[[:space:]]*([^[:space:]]+[[:space:]]+){4}", "", 1);
   print $1, $2, $4, tail, $3 }'

A;B;DD;e       f g    f;c

Dies wäre beeindruckender, wenn ich das Literal kopieren / einfügen und zeigen könnte, dass es in der Ausgabe durchgekommen ist. Tippe eins in bash mit ^ Q. ctrl-Q bedeutet Zitieren Sie den nächsten Tastendruck als wörtliches Zeichen, da die Zeilenbearbeitung im Emacs-Stil von bash mit der von Emacs identisch ist.

http://mywiki.wooledge.org/BashFAQ enthält einige nützliche Informationen zum Thema Skripterstellung, die unabhängig davon, welche Daten oder Dateinamen Sie in das Skript einfügen, keine Probleme verursachen.

Peter Cordes
quelle