Wie kann der Befehl 'cut' dieselben sequentiellen Trennzeichen wie eines behandeln?

309

Ich versuche, ein bestimmtes (viertes) Feld aus dem spaltenbasierten, an das Leerzeichen angepassten Textstrom zu extrahieren. Ich versuche, den cutBefehl folgendermaßen zu verwenden:

cat text.txt | cut -d " " -f 4

Behandelt leider cutnicht mehrere Leerzeichen als ein Trennzeichen. Ich hätte durch awk pfeifen können

awk '{ printf $4; }'

oder sed

sed -E "s/[[:space:]]+/ /g"

um die Leerzeichen zu kollabieren, aber ich würde gerne wissen, ob es eine Möglichkeit gibt, mit cutund mehreren Begrenzern nativ umzugehen ?

mbaitoff
quelle
12
AWK ist der richtige Weg.
Bis auf weiteres angehalten.

Antworten:

546

Versuchen:

tr -s ' ' <text.txt | cut -d ' ' -f4

Von der trManpage:

-s, --squeeze-repeats ersetzen jede Eingabesequenz eines wiederholten Zeichens
                        das ist in SET1 mit einem einzigen Vorkommen aufgeführt
                        dieses Charakters
kev
quelle
24
Keine Notwendigkeit für cathier. Sie könnten < text.txtdirekt an übergeben tr. en.wikipedia.org/wiki/Cat_%28Unix%29#Useless_use_of_cat
Arielf
1
Ich bin mir nicht sicher, ob es einfacher ist, aber Sie werden zusammenführen. Sie können auf Schnitte verzichten -dund direkt von mehreren Zeichen auf die Registerkarte übersetzen. Zum Beispiel: Ich bin hierher gekommen, um nach einer Möglichkeit zu suchen, meine Anzeige automatisch zu exportieren:who am i | tr -s ' ()' '\t' | cut -f5
Leo
Dies entfernt im Gegensatz zur awk-Lösung keine führenden / nachfolgenden Leerzeichen (die möglicherweise erwünscht sind oder nicht, aber normalerweise nicht). Die awk-Lösung ist auch viel besser lesbar und weniger ausführlich.
n.caillou
-1 WARNUNG: Dies ist nicht dasselbe wie die Behandlung von sequenziellen Begrenzern wie einer. Vergleiche echo "a b c" | cut -d " " -f2-,echo "a b c" | tr -s " " | cut -d " " -f2-
user541686
96

Wie Sie in Ihrer Frage kommentieren, awkist wirklich der richtige Weg. Die Verwendung cutist zusammen mit tr -sdem Drücken von Leerzeichen möglich, wie die Antwort von kev zeigt.

Lassen Sie mich jedoch alle möglichen Kombinationen für zukünftige Leser durchgehen. Erläuterungen finden Sie im Abschnitt Test.

tr | Schnitt

tr -s ' ' < file | cut -d' ' -f4

awk

awk '{print $4}' file

Bash

while read -r _ _ _ myfield _
do
   echo "forth field: $myfield"
done < file

sed

sed -r 's/^([^ ]*[ ]*){3}([^ ]*).*/\2/' file

Tests

Testen wir anhand dieser Datei die folgenden Befehle:

$ cat a
this   is    line     1 more text
this      is line    2     more text
this    is line 3     more text
this is   line 4            more    text

tr | Schnitt

$ cut -d' ' -f4 a
is
                        # it does not show what we want!


$ tr -s ' ' < a | cut -d' ' -f4
1
2                       # this makes it!
3
4
$

awk

$ awk '{print $4}' a
1
2
3
4

Bash

Dies liest die Felder nacheinander. Durch die Verwendung geben _wir an, dass dies eine Wegwerfvariable als "Junk-Variable" ist, um diese Felder zu ignorieren. Auf diese Weise speichern wir $myfieldals 4. Feld in der Datei, unabhängig von den Leerzeichen dazwischen.

$ while read -r _ _ _ a _; do echo "4th field: $a"; done < a
4th field: 1
4th field: 2
4th field: 3
4th field: 4

sed

Dies fängt drei Gruppen von Räumen und keine Räume mit ([^ ]*[ ]*){3}. Dann fängt es alles ein, was kommt, bis ein Leerzeichen als 4. Feld, mit dem es schließlich gedruckt wird \1.

$ sed -r 's/^([^ ]*[ ]*){3}([^ ]*).*/\2/' a
1
2
3
4
fedorqui 'SO hör auf zu schaden'
quelle
2
awkist nicht nur elegant und einfach, sondern auch in VMware ESXi enthalten, wo tres fehlt.
user121391
2
@ user121391 noch ein Grund zu verwenden awk!
Fedorqui 'SO hör auf zu schaden'
@fedorqui Ich habe noch nie von dem Unterstrich als "Junk-Variable" gehört. Können Sie hierzu weitere Einblicke / Hinweise geben?
BryKKan
1
@BryKKan Ich habe es in Greg's erfahren. Wie kann ich eine Datei (Datenstrom, Variable) Zeile für Zeile (und / oder Feld für Feld) lesen? : Einige Leute verwenden die Wegwerfvariable _ als "Junk-Variable", um Felder zu ignorieren. Es (oder in der Tat jede Variable) kann auch mehrmals in einem einzelnen readBefehl verwendet werden, wenn es uns egal ist, was darin enthalten ist . Es kann alles sein, es ist nur so, dass es irgendwie zum Standard wurde junk_varoder whatever:)
fedorqui 'SO hör auf, '15.
25

kürzeste / freundlichste Lösung

Nachdem cutich mit den zu vielen Einschränkungen von frustriert war , schrieb ich meinen eigenen Ersatz, den ich als cuts"Schnitt gegen Steroide" bezeichnete.

Schnitte bieten die wahrscheinlich minimalistischste Lösung für dieses und viele andere damit verbundene Probleme beim Ausschneiden / Einfügen.

Ein Beispiel von vielen, das sich mit dieser speziellen Frage befasst:

$ cat text.txt
0   1        2 3
0 1          2   3 4

$ cuts 2 text.txt
2
2

cuts unterstützt:

  • automatische Erkennung der gängigsten Feldbegrenzer in Dateien (+ Möglichkeit, Standardeinstellungen zu überschreiben)
  • Übereinstimmende Trennzeichen für mehrere Zeichen, gemischte Zeichen und Regex
  • Extrahieren von Spalten aus mehreren Dateien mit gemischten Trennzeichen
  • Offsets vom Zeilenende (mit negativen Zahlen) zusätzlich zum Zeilenanfang
  • Automatisches Einfügen von Spalten nebeneinander (kein pasteseparater Aufruf erforderlich )
  • Unterstützung für die Neuordnung vor Ort
  • Eine Konfigurationsdatei, in der Benutzer ihre persönlichen Einstellungen ändern können
  • große Betonung auf Benutzerfreundlichkeit und minimalistisches Tippen

und vieles mehr. Keines davon ist standardmäßig vorgesehen cut.

Siehe auch: https://stackoverflow.com/a/24543231/1296044

Quelle und Dokumentation (freie Software): http://arielf.github.io/cuts/

arielf
quelle
4

Dieser Perl-Einzeiler zeigt, wie eng Perl mit awk verwandt ist:

perl -lane 'print $F[3]' text.txt

Das @FAutosplit-Array beginnt jedoch am Index, $F[0]während awk-Felder mit beginnen$1

Chris Koknat
quelle
3

Mit Versionen von cut, von denen ich weiß, nein, das ist nicht möglich. cutDies ist in erster Linie nützlich, um Dateien zu analysieren, bei denen das Trennzeichen kein Leerzeichen ist (z. B. /etc/passwd) und die eine feste Anzahl von Feldern haben. Zwei Trennzeichen in einer Reihe bedeuten ein leeres Feld, und das gilt auch für Leerzeichen.

Benoit
quelle