Ich habe eine Datei mit vielen Zeilen in jeder Zeile. Es gibt viele Spalten (Felder), die durch Leerzeichen getrennt sind. Die Anzahl der Spalten in jeder Zeile ist unterschiedlich. Ich möchte die ersten beiden Spalten entfernen. Wie geht das?
Ich habe eine Datei mit vielen Zeilen in jeder Zeile. Es gibt viele Spalten (Felder), die durch Leerzeichen getrennt sind. Die Anzahl der Spalten in jeder Zeile ist unterschiedlich. Ich möchte die ersten beiden Spalten entfernen. Wie geht das?
Antworten:
Sie können es tun mit cut
:
cut -d " " -f 3- input_filename > output_filename
Erläuterung:
cut
: Rufen Sie den Befehl cut auf-d " "
: Verwenden Sie ein einzelnes Leerzeichen als Trennzeichen ( cut
verwendet standardmäßig TAB)-f
: Felder angeben, die beibehalten werden sollen3-
: Alle Felder beginnend mit Feld 3input_filename
: Verwenden Sie diese Datei als Eingabe> output_filename
: Schreibe die Ausgabe in diese Datei.Alternativ können Sie dies tun mit awk
:
awk '{$1=""; $2=""; sub(" ", " "); print}' input_filename > output_filename
Erläuterung:
awk
: Rufen Sie den Befehl awk auf$1=""; $2="";
: Setzen Sie Feld 1 und 2 auf die leere Zeichenfolgesub(...);
: Bereinigen Sie die Ausgabefelder, da die Felder 1 und 2 weiterhin durch "" begrenzt werden.print
: Drucke die geänderte Zeileinput_filename > output_filename
: das gleiche wie oben.cut
standardmäßig tab als Trennzeichen verwendet. Siehe aktualisierte Antwort - gerade getestet und es funktioniert. Wenn alles andere gleich ist, würde ich empfehlen, cut
over zu verwenden awk
.
awk '{sub(/([^ ]+ ){2}/, "")}1'
. Ich bin damit einverstanden, dass Schnitt sowieso die bessere Wahl ist, wenn Sie ein Einzelzeichen-Feldtrennzeichen haben.
awk '{$1=""; $2=""; sub(/^ +/, ""); print}'
stattdessen oder kürzerawk '{$1=$2=""; sub(/^ +/, "")}1'
Hier ist eine Möglichkeit, dies mit Awk zu tun, die relativ einfach zu verstehen ist:
awk '{print substr($0, index($0, $3))}'
Dies ist ein einfacher awk-Befehl ohne Muster, sodass {}
für jede Eingabezeile eine Aktion ausgeführt wird.
Die Aktion besteht darin, den Teilstring einfach beginnend mit der Position des 3. Felds zu drucken.
$0
: die gesamte Eingabezeile$3
: 3. Feldindex(in, find)
: Gibt die Position von find
in string zurückin
substr(string, start)
: Rückgabe eines Teilstrings ab Index start
Wenn Sie ein anderes Trennzeichen wie Komma verwenden möchten, können Sie es mit der Option -F angeben:
awk -F"," '{print substr($0, index($0, $3))}'
Sie können dies auch für eine Teilmenge der Eingabezeilen ausführen, indem Sie vor der Aktion in ein Muster angeben {}
. Nur Linien, die dem Muster entsprechen, werden ausgeführt.
awk 'pattern{print substr($0, index($0, $3))}'
Wo Muster etwas sein kann wie:
/abcdef/
: Verwenden Sie einen regulären Ausdruck, arbeitet standardmäßig mit $ 0.$1 ~ /abcdef/
: auf einem bestimmten Feld arbeiten.$1 == blabla
: String-Vergleich verwendenNR > 1
: Datensatz- / Zeilennummer verwendenNF > 0
: Feld- / Spaltennummer verwendenVielen Dank für die Veröffentlichung der Frage. Ich möchte auch das Skript hinzufügen, das mir geholfen hat.
awk '{ $1=""; print $0 }' file
OFS=FS
, um die Trennzeichen beizubehalten
awk '{$1=$2="";$0=$0;$1=$1}1'
Eingang
a b c d
Ausgabe
c d
$0=$0;$1=$1
dass die Leerzeichen verschwinden
Sie können verwenden sed
:
sed 's/^[^ ][^ ]* [^ ][^ ]* //'
Dies sucht nach Zeilen, die mit einem oder mehreren Nicht-Leerzeichen, einem Leerzeichen, einem weiteren Satz von einem oder mehreren Nicht-Leerzeichen und einem weiteren Leerzeichen beginnen, und löscht das übereinstimmende Material, auch bekannt als die ersten beiden Felder. Das [^ ][^ ]*
ist geringfügig kürzer als die entsprechende, aber explizitere [^ ]\{1,\}
Notation, und das zweite kann auf Probleme mit GNU stoßen sed
(wenn Sie es --posix
als Option verwenden, sed
kann es sogar GNU nicht vermasseln). OTOH, wenn die zu wiederholende Zeichenklasse komplexer war, gewinnt die nummerierte Notation der Kürze halber. Es ist einfach, dies zu erweitern, um "Leerzeichen oder Tabulatoren" als Trennzeichen oder "mehrere Leerzeichen" oder "mehrere Leerzeichen oder Registerkarten" zu behandeln. Es kann auch geändert werden, um optionale führende Leerzeichen (oder Tabulatoren) vor dem ersten Feld usw. zu behandeln.
Für awk
und cut
finden Sampson-Chen ‚s Antwort . Es gibt andere Möglichkeiten, das awk
Skript zu schreiben , aber sie sind nicht wesentlich besser als die gegebene Antwort. Beachten Sie, dass Sie das Feldtrennzeichen möglicherweise explizit ( -F" "
) festlegen müssen, awk
wenn Sie nicht möchten, dass Registerkarten als Trennzeichen behandelt werden, oder wenn zwischen den Feldern mehrere Leerzeichen stehen. Der POSIX-Standard cut
unterstützt nicht mehrere Trennzeichen zwischen Feldern. GNU cut
verfügt über die nützliche, aber nicht standardmäßige -i
Option, um mehrere Trennzeichen zwischen Feldern zuzulassen.
Sie können es auch in reiner Schale tun:
while read junk1 junk2 residue
do echo "$residue"
done < in-file > out-file
residue
ein Backslash enthalten kann, wird dieser durch den obigen Lesevorgang interpretiert und nicht in der Ausgabe reproduziert. Immer benutzen while IFS= read -r ...
.
bash
der Inhalt mit einer Ebene interpretiert wird read
, bash
ist er (erneut) fehlerhaft. Der Lesebefehl in Original-Shells hat keinen solchen Unsinn gemacht. Ich glaube nicht, dass es von der POSIX-Shell benötigt wird. Es würde mich irritieren, wenn ich finde, dass bash
es das tut, was Sie sagen - ich habe bereits eine Hassliebe zu dem Programm, da es viele Dinge gut macht, aber es gibt einige Dinge, die es schlecht macht und sich ändert Legacy-Verhalten ist eines der schlimmsten, und die Anforderung einer Option zur Aktivierung des alten Standardverhaltens ist ... sehr irritierend. Es scheint, du hast recht; bash
ist gegabelt!
residue
bei Feld 4 (oder höher) anstelle von Feld 3 beginnen würde .
bash
folgt aber POSIX 2008. Ich wollte diese Funktionalität in mehr als einem Vierteljahrhundert der Shell-Programmierung nie, aber ich denke, ich muss in einer Minderheit sein.
Es ist ziemlich einfach, es nur mit Shell zu machen
while read A B C; do
echo "$C"
done < oldfile >newfile
read -r
anstelle von verwenden möchten read
.
read -r
bewahrt Backslashes. read
wird nicht. Zum Beispiel: echo "foo ba\r"
erzeugt eine Ausgabe von foo ba\r
. Allerdings echo "foo ba\r" | (while read first_column second_column; do echo "$second_column"; done)
produziert nur bar
als der Ausgang (mit dem umgekehrten Schrägstrich entfernt , um das Hinzufügen von . -r
Flagge der korrekte Ausgabe von produziertba\r
Wenn Sie awk verwenden und auf einigen der folgenden Optionen basieren, wird die Verwendung einer for-Schleife etwas flexibler. Manchmal möchte ich vielleicht die ersten 9 Spalten löschen (wenn ich zum Beispiel ein "ls -lrt" mache), also ändere ich die 2 gegen eine 9 und das war's:
awk '{ for(i=0;i++<2;){$i=""}; print $0 }' your_file.txt
Verwenden Sie kscript
kscript 'lines.split().select(-1,-2).print()' file