
Ich habe ein Problem, da ich mit awk nicht vertraut bin. Ich habe eine CSV-Datei, die aus der Ausgabe von sar -d generiert und in den CSV-Stil konvertiert wurde:
12:33:41 unix,restarts
12:35:00,lofi4096,0,0.0,0,0,0.0,0.0
,iscsi0,0,0.0,0,0,0.0,0.0
,scsi_vhc,0,0.0,0,0,0.0,0.0
,nfs1,0,0.0,0,0,0.0,0.0
12:45:00,lofi4096,0,0.0,0,0,0.0,0.0
,iscsi0,0,0.0,0,0,0.0,0.0
,scsi_vhc,0,0.0,0,0,0.0,0.0
,nfs1,0,0.0,0,0,0.0,0.0
und ich möchte dazu konvertieren
12:33:41 unix,restarts
12:35:00,lofi4096,0,0.0,0,0,0.0,0.0
12:35:00,iscsi0,0,0.0,0,0,0.0,0.0
12:35:00,scsi_vhc,0,0.0,0,0,0.0,0.0
12:35:00,nfs1,0,0.0,0,0,0.0,0.0
12:45:00,lofi4096,0,0.0,0,0,0.0,0.0
12:45:00,iscsi0,0,0.0,0,0,0.0,0.0
12:45:00,scsi_vhc,0,0.0,0,0,0.0,0.0
12:45:00,nfs1,0,0.0,0,0,0.0,0.0
Mein Versuch, aber da awk Zeile für Zeile liest, weiß ich nicht, wie ich den Wert der vorherigen Zeile beibehalten soll. Ich würde erwarten, dass das, was ich habe, funktionieren sollte. Irgendeine Idee, wie ich das gewünschte Ergebnis erzielen kann? Ich habe es mit awk versucht, aber ich denke, das sollte mit sed oder auf die harte Tour mit einem benutzerdefinierten Shell-Skript möglich sein (ich versuche, diesen Teil zu vermeiden).
#!/usr/bin/awk -f
BEGIN {
FS=",";
}
{
print $1
if ($1 != "") {
mydate=$1;
print $0;
}
else {
print $mydate","$0;
}
}
Ausführen des Systems mit Solaris 11.1.
Antwort1
Es wird etwas lang, da die Eingabe scheinbar leere Zeilen enthält. Folgendes könnte für Sie funktionieren:
awk -F'[, ]' '{if (NF!=0 && $1=="") {$1=prev} prev=$1}1' OFS=, inputfile
Die Idee ist, Felder und Leerzeichen aufzuteilen ,
(letzteres, um die erste Eingabezeile zu verarbeiten). Überprüfen Sie, ob das erste Feld leer istUnddie Anzahl der Felder ungleich Null ist (Leerzeilen behandeln), dann das erste Feld durch das zuvor gespeicherte erste Feld ersetzen.
Für Ihre Eingabe würde das Ergebnis lauten:
12:33:41 unix,restarts
12:35:00,lofi4096,0,0.0,0,0,0.0,0.0
12:35:00,iscsi0,0,0.0,0,0,0.0,0.0
12:35:00,scsi_vhc,0,0.0,0,0,0.0,0.0
12:35:00,nfs1,0,0.0,0,0,0.0,0.0
12:45:00,lofi4096,0,0.0,0,0,0.0,0.0
12:45:00,iscsi0,0,0.0,0,0,0.0,0.0
12:45:00,scsi_vhc,0,0.0,0,0,0.0,0.0
12:45:00,nfs1,0,0.0,0,0,0.0,0.0
Antwort2
Mit sed
:
sed '/^[0-9]/{ # if line starts with digit
h # overwrite hold buffer with pattern space content
s/\([^,]*\),.*/\1/ # extract timestamp
x # exchange: put the original line back into pattern
} # space and the timestamp in hold space
/^,/{ # if line starts with a comma
G # append hold space (timestamp) to pattern space
s/\(.*\)\n\(.*\)/\2\1/ # swap the initial line content and the timestamp
}' infile
in einer Zeile:
sed -e'/^[0-9]/{h;s/\([^,]*\),.*/\1/;x' -e\} -e'/^,/{G;s/\(.*\)\n\(.*\)/\2\1/' -e\} infile
Antwort3
Ein anderer sed
:
sed '$!N;/\n,/s/\([^,]*\).*\n/&\1/;P;D' <in >out
Für jede Eingabezeile, die !
nicht die $
letzte ist, wird die ext-Eingabezeile an den Musterraum sed
angehängt , dem ein ewline-Zeichen vorangestellt ist. Anschließend wird ein Ersetzungsversuch unternommen, bei dem die erste mögliche Gruppe von Zeichen, die kein Komma sind, in den Raum direkt vor einem Komma kopiert wird, das unmittelbar auf eine ewline folgt. Wenn dies nicht möglich ist, ist wohl kein Schaden entstanden.N
\n
s///
^,
\n
sed
wird dann bis zur ersten neuen Zeile im Musterbereich P
gedruckt und diese gelöscht, bevor der Zyklus mit dem nächsten Paar Eingabezeilen von vorne erneut begonnen wird.\n
D
AUSGABE
12:33:41 unix,restarts
12:35:00,lofi4096,0,0.0,0,0,0.0,0.0
12:35:00,iscsi0,0,0.0,0,0,0.0,0.0
12:35:00,scsi_vhc,0,0.0,0,0,0.0,0.0
12:35:00,nfs1,0,0.0,0,0,0.0,0.0
12:45:00,lofi4096,0,0.0,0,0,0.0,0.0
12:45:00,iscsi0,0,0.0,0,0,0.0,0.0
12:45:00,scsi_vhc,0,0.0,0,0,0.0,0.0
12:45:00,nfs1,0,0.0,0,0,0.0,0.0