Wie kann ich mit sedoder eine CSV-Datei bearbeiten awk?
- Löschen Sie eine Spalte
- Duplizieren Sie eine Spalte
- Eine Spalte verschieben
Ich habe einen großen Tisch mit über 200 Zeilen und bin damit nicht so vertraut sed.
Wie kann ich mit sedoder eine CSV-Datei bearbeiten awk?
Ich habe einen großen Tisch mit über 200 Zeilen und bin damit nicht so vertraut sed.
Antworten:
Abgesehen davon, wie Sie die Felder ausschneiden und neu anordnen (siehe die anderen Antworten), gibt es auch das Problem der skurrilen CSV-Felder.
Wenn Sie Ihre Daten in dieser „quirky“ Kategorie fällt, ein bisschen vor und Post - Filterung kann sich darum kümmern. Die Filter unten erfordern die Zeichen \x01, \x02, \x03, \x04nicht überall in Ihren Daten erscheinen.
Hier sind die Filter, die um einen einfachen Feldspeicherauszug gewickelt sind awk.
Hinweis: Feld 5 hat ein ungültiges / unvollständiges Layout für Felder in Anführungszeichen, ist jedoch am Ende einer Zeile harmlos (abhängig vom CSV-Parser). Aber natürlich wäre es verursacht problematisch unexpedted Ergebnisse , wenn sie von ihrem aktuellen werden sollten getauscht weg End-of-Row - Position.
Aktualisieren; user121196 hat auf einen Fehler hingewiesen, wenn vor einem nachgestellten Anführungszeichen ein Komma steht. Hier ist die Lösung.
Die Daten
cat <<'EOF' >file
field one,"fie,ld,two",field"three","field,\",four","field,five
"15111 N. Hayden Rd., Ste 160,",""
EOF
Der Code
sed -r 's/^/,/; s/\\"/\x01/g; s/,"([^"]*)"/,\x02\1\x03/g; s/,"/,\x02/; :MC; s/\x02([^\x03]*),([^\x03]*)/\x02\1\x04\2/g; tMC; s/^,// ' file |
awk -F, '{ for(i=1; i<=NF; i++) printf "%s\n", $i; print NL}' |
sed -r 's/\x01/\\"/g; s/(\x02|\x03)/"/g; s/\x04/,/g'
Die Ausgabe:
field one
"fie,ld,two"
field"three"
"field,\",four"
"field,five
"15111 N. Hayden Rd., Ste 160,"
""
Hier ist der Vorfilter , erweitert mit Kommentaren.
Der Nachfilter ist nur eine Umkehrung von \x01. \x02, \x03,\x04
sed -r '
s/^/,/ # add a leading comma delimiter
s/\\"/\x01/g # obfuscate escaped quotation-mark (\")
s/,"([^"]*)"/,\x02\1\x03/g # obfuscate quotation-marks
s/,"/,\x02/ # when no trailing quote on last field
:MC # obfuscate commas embedded in quotes
s/\x02([^\x03]*),([^\x03]*)/\x02\1\x04\2/g
tMC
s/^,// # remove spurious leading delimiter
'
Dies hängt davon ab, ob Ihre CSV-Datei Kommas nur für Trennzeichen verwendet oder ob Sie den Wahnsinn haben:
Feld eins, "Feld zwei", Feld drei
Dies setzt voraus, dass Sie eine einfache CSV-Datei verwenden:
Sie können eine einzelne Spalte auf viele Arten loswerden. Ich habe als Beispiel Spalte 2 verwendet. Am einfachsten ist wahrscheinlich die Verwendung cut, mit der Sie ein Trennzeichen angeben -dund welche Felder Sie drucken möchten -f. Dies teilt es in Kommas und Ausgabefeld 1 und die Felder 3 bis zum Ende auf:
$ cut -d, -f1,3- /path/to/your/file
Wenn Sie tatsächlich verwenden müssen sed, können Sie einen regulären Ausdruck schreiben, der mit den ersten n-1Feldern, dem nth-Feld und dem Rest übereinstimmt , und die Ausgabe des nth -Felds überspringen (hier nist 2, damit die erste Gruppe nach 1Zeit abgeglichen wird:) \{1\}:
$ sed 's/\(\([^,]\+,\)\{1\}\)[^,]\+,\(.*\)/\1\3/' /path/to/your/file
Dafür gibt es eine Reihe von Möglichkeiten awk, von denen keine besonders elegant ist. Sie können eine forSchleife verwenden, aber mit dem nachgestellten Komma umzugehen ist ein Schmerz; ignorieren, dass es so etwas wie wäre:
$ awk -F, '{for(i=1; i<=NF; i++) if(i != 2) printf "%s,", $i; print NL}' /path/to/your/file
Ich finde es einfacher, Feld 1 auszugeben und dann substralles nach Feld 2 abzurufen:
$ awk -F, '{print $1 "," substr($0, length($1)+length($2)+3)}' /path/to/your/file
Dies ist jedoch für weiter entfernte Kolumnen ärgerlich
In seddieser ist im Wesentlichen der gleiche Ausdruck wie zuvor, aber Sie auch die Zielspalt erfassen und umfassen die Gruppe mehrfach in dem Ersatz:
$ sed 's/\(\([^,]\+,\)\{1\}\)\([^,]\+,\)\(.*\)/\1\3\3\4/' /path/to/your/file
In awkder for-Schleife wäre es so etwas wie (wieder ohne das nachstehende Komma):
$ awk -F, '{
for(i=1; i<=NF; i++) {
if(i == 2) printf "%s,", $i;
printf "%s,", $i
}
print NL
}' /path/to/your/file
Der substrWeg:
$ awk -F, '{print $1 "," $2 "," substr($0, length($1)+2)}' /path/to/your/file
(tcdyl hat in seiner Antwort eine bessere Methode gefunden )
Ich denke, die sedLösung folgt natürlich aus den anderen, aber es wird langsam lächerlich lang
awkist Ihre beste Wette. awkdruckt Felder nach Nummer, also ...
awk 'BEGIN { FS=","; OFS=","; } {print $1,$2,$3}' file
So entfernen Sie eine Spalte, ohne sie zu drucken:
awk 'BEGIN { FS=","; OFS=","; } {print $1,$3}' file
So ändern Sie die Reihenfolge:
awk 'BEGIN { FS=","; OFS=","; } {print $3,$1,$2}' file
Umleiten in eine Ausgabedatei.
awk 'BEGIN { FS=","; OFS=","; } {print $3,$1,$2}' file > output.file
awk kann auch die Ausgabe formatieren.
Gegeben sei eine durch Leerzeichen getrennte Datei im folgenden Format:
1 2 3 4 5
Sie können Feld 2 mit awk wie folgt entfernen:
awk '{ sub($2,""); print}' file
was zurückkehrt
1 3 4 5
Ersetzen Sie Spalte 2 gegebenenfalls durch Spalte n.
So duplizieren Sie Spalte 2:
awk '{ col = $2 " " $2; $2 = col; print }' file
was zurückkehrt
1 2 2 3 4 5
So wechseln Sie zwischen Spalte 2 und 3:
awk '{temp = $2; $2 = $3; $3 = temp; print}'
was zurückkehrt
1 3 2 4 5
awk ist generell sehr gut im Umgang mit dem Feldbegriff . Wenn Sie mit einer CSV-Datei und nicht mit einer durch Leerzeichen getrennten Datei arbeiten, können Sie sie einfach verwenden
awk -F,
Definieren Sie Ihr Feld als Komma anstelle eines Leerzeichens (dies ist die Standardeinstellung). Es gibt eine Reihe guter awk-Ressourcen online, von denen ich eine unten als Quelle aufführe.
Quelle für # 3
awk, aber es scheint eine durch Leerzeichen getrennte Ausgabe zu geben, auch wenn das Feldtrennzeichen ,(das Feldtrennzeichen steuert nur, wie es die Eingabe behandelt)
Dies funktioniert zum Löschen
awk '{$2="";$0=$0;$1=$1}1'
Eingang
a b c d
Ausgabe
a c d