Der Cut-Befehl ist das kanonische Werkzeug, um „Spalten“ aus einer Textdatei zu entfernen. In diesem Zusammenhang kann eine „Spalte“ als eine Reihe von Zeichen oder Bytes definiert werden, die durch ihre physische Position auf der Zeile identifiziert werden, oder als eine Reihe von Feldern, die durch ein Trennzeichen begrenzt sind.
Ich habe bereits früher über die Verwendung von AWK-Befehlen geschrieben. In dieser ausführlichen Anleitung erkläre ich vier wesentliche und praktische Beispiele für den Befehl cut in Linux, die Ihnen sehr helfen werden.
4 Praktische Beispiele für den Cut-Befehl unter Linux
Wenn Sie es vorziehen, können Sie sich dieses Video ansehen, in dem die gleichen praktischen Beispiele für Schnittbefehle erklärt werden, die ich im Artikel aufgelistet habe.
1. Arbeiten mit Zeichenbereichen
Bei Aufruf mit -c
Befehlszeilenoption entfernt der Cut-Befehl Zeichen Bereiche.
Wie jeder andere Filter ändert auch der Cut-Befehl die vorhandene Eingabedatei nicht, sondern kopiert die geänderten Daten in die Standardausgabe. Es liegt in Ihrer Verantwortung, die Befehlsausgabe in eine Datei umzuleiten, um das Ergebnis zu speichern, oder eine Pipe zu verwenden, um es als Eingabe an einen anderen Befehl zu senden.
Wenn Sie die im obigen Video verwendeten Beispiel-Testdateien heruntergeladen haben, können Sie die BALANCE.txt
sehen Datendatei, die direkt aus einer Buchhaltungssoftware stammt, die meine Frau bei ihrer Arbeit verwendet:
sh$ head BALANCE.txt
ACCDOC ACCDOCDATE ACCOUNTNUM ACCOUNTLIB ACCDOCLIB DEBIT CREDIT
4 1012017 623477 TIDE SCHEDULE ALNEENRE-4701-LOC 00000001615,00
4 1012017 445452 VAT BS/ENC ALNEENRE-4701-LOC 00000000323,00
4 1012017 4356 PAYABLES ALNEENRE-4701-LOC 00000001938,00
5 1012017 623372 ACCOMODATION GUIDE ALNEENRE-4771-LOC 00000001333,00
5 1012017 445452 VAT BS/ENC ALNEENRE-4771-LOC 00000000266,60
5 1012017 4356 PAYABLES ALNEENRE-4771-LOC 00000001599,60
6 1012017 4356 PAYABLES FACT FA00006253 - BIT QUIROBEN 00000001837,20
6 1012017 445452 VAT BS/ENC FACT FA00006253 - BIT QUIROBEN 00000000306,20
6 1012017 623795 TOURIST GUIDE BOOK FACT FA00006253 - BIT QUIROBEN 00000001531,00
Dies ist eine Textdatei mit fester Breite, da die Datenfelder mit einer variablen Anzahl von Leerzeichen aufgefüllt werden, um sicherzustellen, dass sie als gut ausgerichtete Tabelle angezeigt werden.
Als Folge davon beginnt und endet eine Datenspalte immer an derselben Zeichenposition in jeder Zeile. Es gibt jedoch einen kleinen Fallstrick:Trotz seines Namens ist der cut
Der Befehl erfordert tatsächlich, dass Sie den Datenbereich angeben, den Sie behalten möchten , nicht der Bereich, den Sie entfernen möchten . Also, wenn ich nur brauche die ACCOUNTNUM
und ACCOUNTLIB
Spalten in der obigen Datendatei würde ich Folgendes schreiben:
sh$ cut -c 25-59 BALANCE.txt | head
ACCOUNTNUM ACCOUNTLIB
623477 TIDE SCHEDULE
445452 VAT BS/ENC
4356 /accountPAYABLES
623372 ACCOMODATION GUIDE
445452 VAT BS/ENC
4356 PAYABLES
4356 PAYABLES
445452 VAT BS/ENC
623795 TOURIST GUIDE BOOK
Was ist ein Bereich?
Wie wir gerade gesehen haben, erfordert der cut-Befehl die Angabe des Bereichs von Daten, die wir behalten möchten. Lassen Sie uns also formeller einführen, was ein Bereich ist:für den cut
Befehl wird ein Bereich durch eine Anfangs- und eine Endposition definiert, die durch einen Bindestrich getrennt sind. Bereiche sind 1-basiert, d. h. das erste Element der Zeile ist die Elementnummer 1, nicht 0. Bereiche sind inklusive:Der Anfang und das Ende werden in der Ausgabe beibehalten, ebenso wie alle Zeichen dazwischen. Es ist ein Fehler, einen Bereich anzugeben, dessen Endposition vor („niedriger“) als seine Startposition liegt. Als Abkürzung können Sie den Anfang oder weglassen Endwert wie in der folgenden Tabelle beschrieben:
a-b
:der Bereich zwischen a und b (einschließlich)a
:entspricht dem Bereicha-a
-b
:Äquivalent zu1-a
b-
:Äquivalent zub-∞
Mit den Ausschneidebefehlen können Sie mehrere Bereiche angeben, indem Sie sie durch ein Komma trennen. Hier sind ein paar Beispiele:
# Keep characters from 1 to 24 (inclusive)
cut -c -24 BALANCE.txt
# Keep characters from 1 to 24 and 36 to 59 (inclusive)
cut -c -24,36-59 BALANCE.txt
# Keep characters from 1 to 24, 36 to 59 and 93 to the end of the line (inclusive)
cut -c -24,36-59,93- BALANCE.txt
Eine Einschränkung (oder Funktion, je nach Sichtweise) des cut
Befehl ist, dass es die Daten niemals neu anordnet . Der folgende Befehl liefert also genau das gleiche Ergebnis wie der vorherige, obwohl die Bereiche in einer anderen Reihenfolge angegeben werden:
cut -c 93-,-24,36-59 BALANCE.txt
Das kannst du ganz einfach mit diff
überprüfen Befehl:
diff -s <(cut -c -24,36-59,93- BALANCE.txt) \
<(cut -c 93-,-24,36-59 BALANCE.txt)
Files /dev/fd/63 and /dev/fd/62 are identical
Ebenso der cut
Befehl dupliziert niemals Daten :
# One might expect that could be a way to repeat
# the first column three times, but no...
cut -c -10,-10,-10 BALANCE.txt | head -5
ACCDOC
4
4
4
5
Erwähnenswert war ein Vorschlag für ein -o
Option, um diese beiden letzten Einschränkungen aufzuheben und den cut
zu ermöglichen Dienstprogramm zum Neuordnen oder Duplizieren von Daten. Dies wurde jedoch vom POSIX-Komiteeabgelehnt, „weil diese Art der Verbesserung außerhalb des Geltungsbereichs des IEEE P1003.2b-Standardentwurfs liegt.“
Ich persönlich kenne keine gekürzte Version, die diesen Vorschlag als Erweiterung implementiert. Aber wenn ja, teilen Sie uns das bitte über den Kommentarbereich mit!
2. Arbeiten mit Byte-Bereichen
Bei Aufruf mit -b
Befehlszeilenoption entfernt der cut-Befehl Byte Bereiche.
Auf den ersten Blick gibt es keinen offensichtlichen Unterschied zwischen Charakter und Byte Bereiche:
sh$ diff -s <(cut -b -24,36-59,93- BALANCE.txt) \
<(cut -c -24,36-59,93- BALANCE.txt)
Files /dev/fd/63 and /dev/fd/62 are identical
Das liegt daran, dass meine Beispieldatendatei die US-ASCII-Zeichenkodierung („charset“) als file -i
verwendet Befehl kann es richtig erraten:
sh$ file -i BALANCE.txt
BALANCE.txt: text/plain; charset=us-ascii
Bei dieser Zeichencodierung gibt es eine Eins-zu-Eins-Zuordnung zwischen Zeichen und Bytes. Mit nur einem Byte können Sie theoretisch bis zu 256 verschiedene Zeichen (Ziffern, Buchstaben, Satzzeichen, Symbole, …) allgemein gefunden). Wie auch immer, selbst wenn wir den vollen Byte-Bereich nutzen könnten, wäre das bei weitem nicht genug, um die Vielfalt der menschlichen Schrift zu speichern. So ist heute die Eins-zu-Eins-Zuordnung zwischen Zeichen und Byte eher die Ausnahme als die Norm und wird fast immer durch die allgegenwärtige UTF-8-Multibyte-Kodierung ersetzt. Sehen wir uns nun an, wie der cut-Befehl damit umgehen könnte.
Arbeiten mit Multibyte-Zeichen
Wie ich bereits sagte, stammen die Beispieldatendateien, die als Beispiele für diesen Artikel verwendet wurden, aus einer Buchhaltungssoftware, die von meiner Frau verwendet wird. Es fügt hinzu, dass sie diese Software kürzlich aktualisiert hat und danach waren die exportierten Textdateien geringfügig anders. Ich lasse Sie versuchen, den Unterschied selbst zu erkennen:
sh$ head BALANCE-V2.txt
ACCDOC ACCDOCDATE ACCOUNTNUM ACCOUNTLIB ACCDOCLIB DEBIT CREDIT
4 1012017 623477 TIDE SCHEDULE ALNÉENRE-4701-LOC 00000001615,00
4 1012017 445452 VAT BS/ENC ALNÉENRE-4701-LOC 00000000323,00
4 1012017 4356 PAYABLES ALNÉENRE-4701-LOC 00000001938,00
5 1012017 623372 ACCOMODATION GUIDE ALNÉENRE-4771-LOC 00000001333,00
5 1012017 445452 VAT BS/ENC ALNÉENRE-4771-LOC 00000000266,60
5 1012017 4356 PAYABLES ALNÉENRE-4771-LOC 00000001599,60
6 1012017 4356 PAYABLES FACT FA00006253 - BIT QUIROBEN 00000001837,20
6 1012017 445452 VAT BS/ENC FACT FA00006253 - BIT QUIROBEN 00000000306,20
6 1012017 623795 TOURIST GUIDE BOOK FACT FA00006253 - BIT QUIROBEN 00000001531,00
Der Titel dieses Abschnitts kann Ihnen dabei helfen, herauszufinden, was sich geändert hat. Aber, gefunden oder nicht, sehen wir uns jetzt die Folgen dieser Änderung an:
sh$ cut -c 93-,-24,36-59 BALANCE-V2.txt
ACCDOC ACCDOCDATE ACCOUNTLIB DEBIT CREDIT
4 1012017 TIDE SCHEDULE 00000001615,00
4 1012017 VAT BS/ENC 00000000323,00
4 1012017 PAYABLES 00000001938,00
5 1012017 ACCOMODATION GUIDE 00000001333,00
5 1012017 VAT BS/ENC 00000000266,60
5 1012017 PAYABLES 00000001599,60
6 1012017 PAYABLES 00000001837,20
6 1012017 VAT BS/ENC 00000000306,20
6 1012017 TOURIST GUIDE BOOK 00000001531,00
19 1012017 SEMINAR FEES 00000000080,00
19 1012017 PAYABLES 00000000080,00
28 1012017 MAINTENANCE 00000000746,58
28 1012017 VAT BS/ENC 00000000149,32
28 1012017 PAYABLES 00000000895,90
31 1012017 PAYABLES 00000000240,00
31 1012017 VAT BS/DEBIT 00000000040,00
31 1012017 ADVERTISEMENTS 00000000200,00
32 1012017 WATER 00000000202,20
32 1012017 VAT BS/DEBIT 00000000020,22
32 1012017 WATER 00000000170,24
32 1012017 VAT BS/DEBIT 00000000009,37
32 1012017 PAYABLES 00000000402,03
34 1012017 RENTAL COSTS 00000000018,00
34 1012017 PAYABLES 00000000018,00
35 1012017 MISCELLANEOUS CHARGES 00000000015,00
35 1012017 VAT BS/DEBIT 00000000003,00
35 1012017 PAYABLES 00000000018,00
36 1012017 LANDLINE TELEPHONE 00000000069,14
36 1012017 VAT BS/ENC 00000000013,83
Oben habe ich die Befehlsausgabe in-extenso kopiert Es sollte also offensichtlich sein, dass bei der Spaltenausrichtung etwas schief gelaufen ist.
Die Erklärung ist, dass die ursprüngliche Datendatei nur US-ASCII-Zeichen enthielt (Symbole, Satzzeichen, Zahlen und lateinische Buchstaben ohne diakritische Zeichen)
Aber wenn Sie sich die nach dem Software-Update erstellte Datei genau ansehen, können Sie sehen, dass die neue Exportdatendatei jetzt Buchstaben mit Akzenten beibehält. Beispielsweise wird das Unternehmen mit dem Namen „ALNÉENRE“ jetzt korrekt geschrieben, während es zuvor als „ALNEENRE“ (ohne Akzent) exportiert wurde
Die file -i
Das Dienstprogramm hat diese Änderung nicht übersehen, da es die Datei jetzt als UTF-8-codiert meldet:
sh$ file -i BALANCE-V2.txt
BALANCE-V2.txt: text/plain; charset=utf-8
Um zu sehen, wie akzentuierte Buchstaben in einer UTF-8-Datei kodiert werden, können wir den hexdump
verwenden Dienstprogramm, mit dem wir direkt auf die Bytes in einer Datei schauen können:
# To reduce clutter, let's focus only on the second line of the file
sh$ sed '2!d' BALANCE-V2.txt
4 1012017 623477 TIDE SCHEDULE ALNÉENRE-4701-LOC 00000001615,00
sh$ sed '2!d' BALANCE-V2.txt | hexdump -C
00000000 34 20 20 20 20 20 20 20 20 20 31 30 31 32 30 31 |4 101201|
00000010 37 20 20 20 20 20 20 20 36 32 33 34 37 37 20 20 |7 623477 |
00000020 20 20 20 54 49 44 45 20 53 43 48 45 44 55 4c 45 | TIDE SCHEDULE|
00000030 20 20 20 20 20 20 20 20 20 20 20 41 4c 4e c3 89 | ALN..|
00000040 45 4e 52 45 2d 34 37 30 31 2d 4c 4f 43 20 20 20 |ENRE-4701-LOC |
00000050 20 20 20 20 20 20 20 20 20 20 20 20 20 30 30 30 | 000|
00000060 30 30 30 30 31 36 31 35 2c 30 30 20 20 20 20 20 |00001615,00 |
00000070 20 20 20 20 20 20 20 20 20 20 20 0a | .|
0000007c
Auf der Zeile 00000030 des hexdump
ausgegeben, nach einer Reihe von Leerzeichen (Byte 20
), können Sie sehen:
- der Buchstabe
A
wird als Byte41
kodiert , - der Buchstabe
L
wird durch das Byte4c
kodiert , - und dem Buchstaben
N
wird als Byte4e
kodiert .
Aber der lateinische Großbuchstabe E mit Akut (da es der offizielle Name des Buchstabens É ist im Unicode-Standard) wird mit den zwei codiert Bytes c3 89
Und hier ist das Problem:die Verwendung des cut
Der Befehl mit Bereichen, die als Byte-Positionen ausgedrückt werden, funktioniert gut für Codierungen mit fester Länge, aber nicht für Codierungen mit variabler Länge wie UTF-8 oder Shift JIS. Dies wird im folgenden nicht normativen Auszug des POSIX-Standards deutlich erklärt:
Frühere Versionen des Cut-Dienstprogramms funktionierten in einer Umgebung, in der Bytes und Zeichen als gleichwertig betrachtet wurden (Modulound -Verarbeitung in einigen Implementierungen). In der erweiterten Welt der Multibyte-Zeichen wurde die neue Option -b hinzugefügt.
He, Moment mal! Ich habe das -b
nicht verwendet Option im „fehlerhaften“ Beispiel oben, aber die -c
Möglichkeit. Also, sollte nicht die funktioniert haben?!?
Ja, das sollte :Es ist bedauerlich, aber wir sind im Jahr 2018 und trotzdem verarbeitet die GNU-Implementierung des Cut-Dienstprogramms ab GNU Coreutils 8.30 Multibyte-Zeichen immer noch nicht richtig. Um die GNU-Dokumentation zu zitieren, der -c
Die Option ist „Vorerst dasselbe wie -b, aber die Internationalisierung wird das ändern[… ]“ — eine Erwähnung, die seit mehr als 10 Jahren besteht!
Andererseits ist die OpenBSD-Implementierung des Cut-Dienstprogramms POSIX-kompatibel und wird die aktuellen Locale-Einstellungen berücksichtigen, um Multi-Byte-Zeichen richtig zu handhaben:
# Ensure subseauent commands will know we are using UTF-8 encoded
# text files
openbsd-6.3$ export LC_CTYPE=en_US.UTF-8
# With the `-c` option, cut works properly with multi-byte characters
openbsd-6.3$ cut -c -24,36-59,93- BALANCE-V2.txt
ACCDOC ACCDOCDATE ACCOUNTLIB DEBIT CREDIT
4 1012017 TIDE SCHEDULE 00000001615,00
4 1012017 VAT BS/ENC 00000000323,00
4 1012017 PAYABLES 00000001938,00
5 1012017 ACCOMODATION GUIDE 00000001333,00
5 1012017 VAT BS/ENC 00000000266,60
5 1012017 PAYABLES 00000001599,60
6 1012017 PAYABLES 00000001837,20
6 1012017 VAT BS/ENC 00000000306,20
6 1012017 TOURIST GUIDE BOOK 00000001531,00
19 1012017 SEMINAR FEES 00000000080,00
19 1012017 PAYABLES 00000000080,00
28 1012017 MAINTENANCE 00000000746,58
28 1012017 VAT BS/ENC 00000000149,32
28 1012017 PAYABLES 00000000895,90
31 1012017 PAYABLES 00000000240,00
31 1012017 VAT BS/DEBIT 00000000040,00
31 1012017 ADVERTISEMENTS 00000000200,00
32 1012017 WATER 00000000202,20
32 1012017 VAT BS/DEBIT 00000000020,22
32 1012017 WATER 00000000170,24
32 1012017 VAT BS/DEBIT 00000000009,37
32 1012017 PAYABLES 00000000402,03
34 1012017 RENTAL COSTS 00000000018,00
34 1012017 PAYABLES 00000000018,00
35 1012017 MISCELLANEOUS CHARGES 00000000015,00
35 1012017 VAT BS/DEBIT 00000000003,00
35 1012017 PAYABLES 00000000018,00
36 1012017 LANDLINE TELEPHONE 00000000069,14
36 1012017 VAT BS/ENC 00000000013,83
Wie erwartet bei Verwendung von -b
Byte-Modus anstelle des -c
Zeichenmodus verhält sich die Cut-Implementierung von OpenBSD wie der alte cut
:
openbsd-6.3$ cut -b -24,36-59,93- BALANCE-V2.txt
ACCDOC ACCDOCDATE ACCOUNTLIB DEBIT CREDIT
4 1012017 TIDE SCHEDULE 00000001615,00
4 1012017 VAT BS/ENC 00000000323,00
4 1012017 PAYABLES 00000001938,00
5 1012017 ACCOMODATION GUIDE 00000001333,00
5 1012017 VAT BS/ENC 00000000266,60
5 1012017 PAYABLES 00000001599,60
6 1012017 PAYABLES 00000001837,20
6 1012017 VAT BS/ENC 00000000306,20
6 1012017 TOURIST GUIDE BOOK 00000001531,00
19 1012017 SEMINAR FEES 00000000080,00
19 1012017 PAYABLES 00000000080,00
28 1012017 MAINTENANCE 00000000746,58
28 1012017 VAT BS/ENC 00000000149,32
28 1012017 PAYABLES 00000000895,90
31 1012017 PAYABLES 00000000240,00
31 1012017 VAT BS/DEBIT 00000000040,00
31 1012017 ADVERTISEMENTS 00000000200,00
32 1012017 WATER 00000000202,20
32 1012017 VAT BS/DEBIT 00000000020,22
32 1012017 WATER 00000000170,24
32 1012017 VAT BS/DEBIT 00000000009,37
32 1012017 PAYABLES 00000000402,03
34 1012017 RENTAL COSTS 00000000018,00
34 1012017 PAYABLES 00000000018,00
35 1012017 MISCELLANEOUS CHARGES 00000000015,00
35 1012017 VAT BS/DEBIT 00000000003,00
35 1012017 PAYABLES 00000000018,00
36 1012017 LANDLINE TELEPHONE 00000000069,14
36 1012017 VAT BS/ENC 00000000013,83
3. Arbeiten mit Feldern
In gewisser Weise ist das Arbeiten mit Feldern in einer Textdatei mit Trennzeichen für den cut
einfacher Dienstprogramm, da es nur die (ein Byte) Feldtrennzeichen in jeder Zeile lokalisieren muss und dann den Feldinhalt wörtlich in die Ausgabe kopiert, ohne sich um Codierungsprobleme zu kümmern.
Hier ist ein Beispiel für eine Textdatei mit Trennzeichen:
sh$ head BALANCE.csv
ACCDOC;ACCDOCDATE;ACCOUNTNUM;ACCOUNTLIB;ACCDOCLIB;DEBIT;CREDIT
4;1012017;623477;TIDE SCHEDULE;ALNEENRE-4701-LOC;00000001615,00;
4;1012017;445452;VAT BS/ENC;ALNEENRE-4701-LOC;00000000323,00;
4;1012017;4356;PAYABLES;ALNEENRE-4701-LOC;;00000001938,00
5;1012017;623372;ACCOMODATION GUIDE;ALNEENRE-4771-LOC;00000001333,00;
5;1012017;445452;VAT BS/ENC;ALNEENRE-4771-LOC;00000000266,60;
5;1012017;4356;PAYABLES;ALNEENRE-4771-LOC;;00000001599,60
6;1012017;4356;PAYABLES;FACT FA00006253 - BIT QUIROBEN;;00000001837,20
6;1012017;445452;VAT BS/ENC;FACT FA00006253 - BIT QUIROBEN;00000000306,20;
6;1012017;623795;TOURIST GUIDE BOOK;FACT FA00006253 - BIT QUIROBEN;00000001531,00;
Sie kennen dieses Dateiformat vielleicht als CSV (für Comma-separated Value), auch wenn das Feldtrennzeichen nicht immer ein Komma ist. Beispielsweise das Semikolon (;
) wird häufig als Feldtrennzeichen verwendet und ist oft die Standardauswahl beim Exportieren von Daten als „CSV“ in Länder, die bereits das Komma als Dezimaltrennzeichen verwenden (wie wir es in Frankreich tun – daher die Wahl dieses Zeichens in meiner Beispieldatei ). Eine andere beliebte Variante verwendet ein Tabulatorzeichen als Feldtrennzeichen, wodurch eine Datei mit tabulatorgetrennten Werten entsteht. Schließlich ist in der Unix- und Linux-Welt der Doppelpunkt (:
) ist ein weiteres relativ gebräuchliches Feldtrennzeichen, das Sie beispielsweise im Standard /etc/passwd
finden können und /etc/group
Dateien.
Wenn Sie ein Textdateiformat mit Trennzeichen verwenden, geben Sie dem Ausschneidebefehl den Feldbereich an, der beibehalten werden soll, indem Sie -f
verwenden Option, und Sie müssen das Trennzeichen mit -d
angeben Option (ohne das -d
Option verwendet das Cut-Dienstprogramm standardmäßig ein Tabulatorzeichen als Trennzeichen):
sh$ cut -f 5- -d';' BALANCE.csv | head
ACCDOCLIB;DEBIT;CREDIT
ALNEENRE-4701-LOC;00000001615,00;
ALNEENRE-4701-LOC;00000000323,00;
ALNEENRE-4701-LOC;;00000001938,00
ALNEENRE-4771-LOC;00000001333,00;
ALNEENRE-4771-LOC;00000000266,60;
ALNEENRE-4771-LOC;;00000001599,60
FACT FA00006253 - BIT QUIROBEN;;00000001837,20
FACT FA00006253 - BIT QUIROBEN;00000000306,20;
FACT FA00006253 - BIT QUIROBEN;00000001531,00;
Handhabungszeilen, die das Trennzeichen nicht enthalten
Was aber, wenn eine Zeile in der Eingabedatei das Trennzeichen nicht enthält? Es ist verlockend, sich das als eine Zeile vorzustellen, die nur das erste Feld enthält. Aber das ist nicht was das Schnittdienstprogramm macht.
Standardmäßig bei Verwendung von -f
Option ausschneiden, gibt das Cut-Dienstprogramm immer wörtlich eine Zeile aus, die das Trennzeichen nicht enthält (wahrscheinlich unter der Annahme, dass dies eine Zeile ohne Daten ist, wie eine Kopfzeile oder eine Art Kommentar):
sh$ (echo "# 2018-03 BALANCE"; cat BALANCE.csv) > BALANCE-WITH-HEADER.csv
sh$ cut -f 6,7 -d';' BALANCE-WITH-HEADER.csv | head -5
# 2018-03 BALANCE
DEBIT;CREDIT
00000001615,00;
00000000323,00;
;00000001938,00
Mit dem -s
können Sie dieses Verhalten umkehren, also cut
wird diese Zeile immer ignorieren:
sh$ cut -s -f 6,7 -d';' BALANCE-WITH-HEADER.csv | head -5
DEBIT;CREDIT
00000001615,00;
00000000323,00;
;00000001938,00
00000001333,00;
Wenn Sie in einer Hacking-Stimmung sind, können Sie diese Funktion als relativ obskuren Weg ausnutzen, um nur Zeilen zu behalten, die ein bestimmtes Zeichen enthalten:
# Keep lines containing a `e`
sh$ printf "%s\n" {mighty,bold,great}-{condor,monkey,bear} | cut -s -f 1- -d'e'
Ausgabetrennzeichen ändern
Als Erweiterung erlaubt die GNU-Implementierung von cut mit dem --output-delimiter
ein anderes Feldtrennzeichen für die Ausgabe zu verwenden Möglichkeit:
sh$ cut -f 5,6- -d';' --output-delimiter="*" BALANCE.csv | head
ACCDOCLIB*DEBIT*CREDIT
ALNEENRE-4701-LOC*00000001615,00*
ALNEENRE-4701-LOC*00000000323,00*
ALNEENRE-4701-LOC**00000001938,00
ALNEENRE-4771-LOC*00000001333,00*
ALNEENRE-4771-LOC*00000000266,60*
ALNEENRE-4771-LOC**00000001599,60
FACT FA00006253 - BIT QUIROBEN**00000001837,20
FACT FA00006253 - BIT QUIROBEN*00000000306,20*
FACT FA00006253 - BIT QUIROBEN*00000001531,00*
Beachten Sie, dass in diesem Fall alle Vorkommen des Feldtrennzeichens ersetzt werden und nicht nur die an der Grenze der Bereiche, die in den Befehlszeilenargumenten angegeben sind.
4. Nicht-POSIX-GNU-Erweiterungen
Apropos Nicht-POSIX-GNU-Erweiterung, ein paar davon können besonders nützlich sein. Erwähnenswert sind die folgenden Erweiterungen, die genauso gut mit Byte-, Zeichen- (was das in der aktuellen GNU-Implementierung bedeutet) oder Feldbereichen funktionieren:--complement
Stellen Sie sich diese Option wie das Ausrufezeichen in einer Sed-Adresse vor (!
); Anstatt die Daten im angegebenen Bereich zu halten, cut
behält Daten, die NICHT mit dem Bereich übereinstimmen
# Keep only field 5
sh$ cut -f 5 -d';' BALANCE.csv |head -3
ACCDOCLIB
ALNEENRE-4701-LOC
ALNEENRE-4701-LOC
# Keep all but field 5
sh$ cut --complement -f 5 -d';' BALANCE.csv |head -3
ACCDOC;ACCDOCDATE;ACCOUNTNUM;ACCOUNTLIB;DEBIT;CREDIT
4;1012017;623477;TIDE SCHEDULE;00000001615,00;
4;1012017;445452;VAT BS/ENC;00000000323,00;
--zero-terminated
(-z
)
Verwenden Sie anstelle des Zeilenumbruchzeichens das NUL-Zeichen als Zeilenabschlusszeichen. Das -z
Die Option ist besonders nützlich, wenn Ihre Daten möglicherweise eingebettete Zeilenumbruchzeichen enthalten, z. B. beim Arbeiten mit Dateinamen (da Zeilenumbruch ein gültiges Zeichen in einem Dateinamen ist, NUL jedoch nicht).
Um Ihnen zu zeigen, wie das -z
Option funktioniert, machen wir ein kleines Experiment. Zuerst erstellen wir eine Datei, deren Name eingebettete neue Zeilen enthält:
bash$ touch
Nehmen wir nun an, ich möchte die ersten 5 Zeichen jeder *.txt
anzeigen Dateinamen. Eine naive Lösung wird hier kläglich scheitern:
sh$ ls -1 *.txt | cut -c 1-5
BALAN
BALAN
EMPTY
FILE
WITH
NAME.
Vielleicht haben Sie ls
bereits gelesen wurde für den menschlichen Gebrauch entwickelt, und die Verwendung in einer Befehlspipeline ist ein Anti-Pattern (das ist es in der Tat). Verwenden wir also den find
Befehl stattdessen:
sh$ find . -name '*.txt' -printf "%f\n" | cut -c 1-5
BALAN
EMPTY
FILE
WITH
NAME.
BALAN
und … das im Grunde das gleiche fehlerhafte Ergebnis wie zuvor erzeugte (allerdings in einer anderen Reihenfolge, weil ls
sortiert implizit die Dateinamen, etwas das find
Befehl geht nicht).
Das Problem ist in beiden Fällen der cut
Der Befehl kann nicht zwischen einem Zeilenumbruchzeichen als Teil eines Datenfelds (dem Dateinamen) und einem Zeilenumbruchzeichen unterscheiden, das als Datensatzende-Markierung verwendet wird. Aber mit dem NUL-Byte (\0
), da der Zeilenabschluss die Verwirrung beseitigt, damit wir endlich das erwartete Ergebnis erhalten:
# I was told (?) some old versions of tr require using \000 instead of \0
# to denote the NUL character (let me know if you needed that change!)
sh$ find . -name '*.txt' -printf "%f\0" | cut -z -c 1-5| tr '\0' '\n'
BALAN
EMPTY
BALAN
Mit diesem letzten Beispiel entfernen wir uns vom Kern dieses Artikels, der der cut
war Befehl. Ich lasse Sie also versuchen, selbst herauszufinden, was der abgefahrene "%f\0"
bedeutet nach dem -printf
Argument von find
Befehl oder warum ich den tr
verwendet habe Befehl am Ende der Pipeline.
Mit dem Cut-Befehl kann noch viel mehr gemacht werden
Ich habe gerade die gebräuchlichste und meiner Meinung nach wichtigste Verwendung des Cut-Befehls gezeigt. Sie können den Befehl noch praktischer anwenden. Es hängt von Ihrem logischen Denken und Ihrer Vorstellungskraft ab.
Zögern Sie nicht, den Kommentarbereich unten zu verwenden, um Ihre Ergebnisse zu veröffentlichen. Und wenn Ihnen dieser Artikel gefällt, vergessen Sie wie immer nicht, ihn auf Ihren bevorzugten Websites und in sozialen Medien zu teilen!