Sortieren mit sed oder awk
Sortieren mit sed oder awk
Wie sortiere ich eine plain-text Datei mit einem Einzeiler nach z. B. dem zweit-letzten oder siebt-letzten "Wort" bzw. string eines Satzes und richte das Ergebnis nicht links- sondern rechtsbündig aus?
Das zweit- oder siebt-letzte Wort besteht aus Buchstaben und Zahlen (a-z, 0-9), aber keine Umlaute und nur Kleinbuchstaben. Es sind keine Spalten wie in einem Server logfile. Ich dachte ich könnte das mit awk lösen in dem ich die Einzelwörter als Spalten wie in einem logfile sehe, aber das funktioniert nicht. Ich habe auch versucht die Leerzeichen zwischen den Wörtern mit einem Punkt zu ersetzen und dann zu sortieren wie eine URL sortiert werden kann, aber das funktioniert nicht.
Das zweit- oder siebt-letzte Wort besteht aus Buchstaben und Zahlen (a-z, 0-9), aber keine Umlaute und nur Kleinbuchstaben. Es sind keine Spalten wie in einem Server logfile. Ich dachte ich könnte das mit awk lösen in dem ich die Einzelwörter als Spalten wie in einem logfile sehe, aber das funktioniert nicht. Ich habe auch versucht die Leerzeichen zwischen den Wörtern mit einem Punkt zu ersetzen und dann zu sortieren wie eine URL sortiert werden kann, aber das funktioniert nicht.
Re: Sortieren mit sed oder awk
Du kannst mit sort -k N nach einer bestimmten Spalte sortieren, wobei N die Spaltennummer ist nach der sortiert werden soll.
Text rechtsbündig ausrichten geht mit sed* [1], wenn du die maximale Zeilenlänge kennst (hier 105):
Die maximale Zeilenlänge kriegst du z.B. mit wc -L heraus. Dabei gibt wc allerdings noch den Dateinamen mit aus, den du wegschneiden musst (z.B. mit grep).
Als "Einzeiler" in bash könnte das Resultat also so aussehen:Mit awk geht das sicher dreimal schöner und kürzer, ber damit stehe ich immer noch auf Kriegsfuß.
*) Ich habe das Beispiel selbst nicht ganz verstanden, da ich mit Scripten und Sprungmarken in sed nicht vertraut bin. Falls das jemand einfach erklären könnte würde ich mich freuen.
[1] http://www-rohan.sdsu.edu/doc/sed.html
Text rechtsbündig ausrichten geht mit sed* [1], wenn du die maximale Zeilenlänge kennst (hier 105):
Code: Alles auswählen
sed -e :a -e 's/^.\{1,105\}$/ &/;ta'
Als "Einzeiler" in bash könnte das Resultat also so aussehen:
Code: Alles auswählen
export WC=`wc -L DATEINAME | egrep -o '^[0-9]+'`; sort -k 2 DATEINAME | sed -e :a -e 's/^.\{1,'$WC'\}$/ &/;ta'
*) Ich habe das Beispiel selbst nicht ganz verstanden, da ich mit Scripten und Sprungmarken in sed nicht vertraut bin. Falls das jemand einfach erklären könnte würde ich mich freuen.
[1] http://www-rohan.sdsu.edu/doc/sed.html
Re: Sortieren mit sed oder awk
Code: Alles auswählen
$ awk 'BEGIN{for(i=0;i<9;i++)printf("foo bar%s baz %d test\n", rand()>0.5?" extra":"", 255*rand())}' >testdata
$ awk '{print($(NF-1), $0)}' <testdata
247 foo bar extra baz 247 test
175 foo bar baz 175 test
120 foo bar extra baz 120 test
164 foo bar extra baz 164 test
99 foo bar baz 99 test
26 foo bar baz 26 test
155 foo bar extra baz 155 test
223 foo bar extra baz 223 test
99 foo bar baz 99 test
$ awk '{print($(NF-1), $0)}' <testdata | sort -n
26 foo bar baz 26 test
99 foo bar baz 99 test
99 foo bar baz 99 test
120 foo bar extra baz 120 test
155 foo bar extra baz 155 test
164 foo bar extra baz 164 test
175 foo bar baz 175 test
223 foo bar extra baz 223 test
247 foo bar extra baz 247 test
$ awk '{print($(NF-1), $0)}' <testdata | sort -n | awk '{$1="";gsub(/^ /,"");print}'
foo bar baz 26 test
foo bar baz 99 test
foo bar baz 99 test
foo bar extra baz 120 test
foo bar extra baz 155 test
foo bar extra baz 164 test
foo bar baz 175 test
foo bar extra baz 223 test
foo bar extra baz 247 test
$
Code: Alles auswählen
$ sort -nk 4,5 <testdata
foo bar extra baz 120 test
foo bar extra baz 155 test
foo bar extra baz 164 test
foo bar extra baz 223 test
foo bar extra baz 247 test
foo bar baz 26 test
foo bar baz 99 test
foo bar baz 99 test
foo bar baz 175 test
$
Fuer das rechtsbuendige Ausrichten wuerde ich %s von printf verwenden:
Code: Alles auswählen
$ awk 'BEGIN{printf("%20s\n", "test")}'
test
$ awk -vcols="$(tput cols)" 'BEGIN{printf("%"cols"s\n", "test")}'
test
$
Code: Alles auswählen
$ awk '{print($(NF-1), $0)}' <testdata | sort -n | awk -vcols="$(tput cols)" '{$1="";gsub(/^ /,"");printf("%"cols"s\n",$0)}'
foo bar baz 26 test
foo bar baz 99 test
foo bar baz 99 test
foo bar extra baz 120 test
foo bar extra baz 155 test
foo bar extra baz 164 test
foo bar baz 175 test
foo bar extra baz 223 test
foo bar extra baz 247 test
$
Gruss Cae
If universal surveillance were the answer, lots of us would have moved to the former East Germany. If surveillance cameras were the answer, camera-happy London, with something like 500,000 of them at a cost of $700 million, would be the safest city on the planet.
—Bruce Schneier
Re: Sortieren mit sed oder awk
Das ist eine Schleife. Das s/// setzt ein Space vorne dran, sofern die Anzahl der Zeichen einer Zeile (innerhalb von ^ und $) zwischen 1 und 105 liegt. Sofern eine erfolgreiche Ersetzung stattfindet, wird durch t (springe zum nachfolgenden Label, sofern letztes s/// matchte) zum Label a gesprungen, welches vorher definiert wurde. Da es selbst leer ist, springt die Codeausfuehrung weiter zum s///. Ein an C angelehnter Pseudocode dazu saehe etwa so aus:hikaru hat geschrieben:Text rechtsbündig ausrichten geht mit sed* [1], wenn du die maximale Zeilenlänge kennst (hier 105):[...]Code: Alles auswählen
sed -e :a -e 's/^.\{1,105\}$/ &/;ta'
*) Ich habe das Beispiel selbst nicht ganz verstanden, da ich mit Scripten und Sprungmarken in sed nicht vertraut bin. Falls das jemand einfach erklären könnte würde ich mich freuen.
Code: Alles auswählen
for each line {
:a
replace(); // s///
if has_matched() // t
goto a;
}
Gruss Cae
If universal surveillance were the answer, lots of us would have moved to the former East Germany. If surveillance cameras were the answer, camera-happy London, with something like 500,000 of them at a cost of $700 million, would be the safest city on the planet.
—Bruce Schneier
Re: Sortieren mit sed oder awk
Ja, die Zählung von hinten hatte ich überlesen.Cae hat geschrieben:sort -k fuehrt offensichtlich nicht zum Ziel, da es von vorne zaehlt:
ret kann laut Manpage keine Felder, nützt also nichts. (Es sei denn das gewünschte Feld enthält nur Palindrome )
Danke!Cae hat geschrieben:Das ist eine Schleife. Das s/// setzt ein Space vorne dran, sofern die Anzahl der Zeichen einer Zeile (innerhalb von ^ und $) zwischen 1 und 105 liegt. Sofern eine erfolgreiche Ersetzung stattfindet, wird durch t (springe zum nachfolgenden Label, sofern letztes s/// matchte) zum Label a gesprungen, welches vorher definiert wurde. Da es selbst leer ist, springt die Codeausfuehrung weiter zum s///.
Re: Sortieren mit sed oder awk
Vielleicht nicht schön. Aber so als Idee.
Trennzeichen ist das Leerzeichen. NF-1 bedeutet die zweitletzte Spalte. Irgendwo muss ja die Information stehen.
Im Prinzip wird die vorletzte Spalte per Leerzeichen getrennt zusätzlich ganz an den Anfang gestellt.
Dann wird sortiert. Und dann wird die erste Spalte wieder weggeworfen
Bei abweichenden Trennzeichen muss die awk-Option -F verwendet werden. Auch muss die printf-Angabe geändert werden.
Nachtrag:
Leider ist cut wohl nicht in der Lage die Funktion von awk abzubilden. Der Aufruf von z.B.
gibt die Spalten jeweils nur einmal aus. Auch funktioniert die Umsortierung nicht.
Trennzeichen ist das Leerzeichen. NF-1 bedeutet die zweitletzte Spalte. Irgendwo muss ja die Information stehen.
Code: Alles auswählen
awk '{print $(NF-1) " " $0}' file|sort |awk '{for (i=2;i<=NF;i++) {printf $i " "}printf "\n" }'
Dann wird sortiert. Und dann wird die erste Spalte wieder weggeworfen
Bei abweichenden Trennzeichen muss die awk-Option -F verwendet werden. Auch muss die printf-Angabe geändert werden.
Nachtrag:
Leider ist cut wohl nicht in der Lage die Funktion von awk abzubilden. Der Aufruf von z.B.
Code: Alles auswählen
cut -d" " -f3,1-4 file
gibt die Spalten jeweils nur einmal aus. Auch funktioniert die Umsortierung nicht.
Re: Sortieren mit sed oder awk
Netter Ansatz!uname hat geschrieben: Im Prinzip wird die vorletzte Spalte per Leerzeichen getrennt zusätzlich ganz an den Anfang gestellt.
Dann wird sortiert. Und dann wird die erste Spalte wieder weggeworfen
Das hast du richtig erkannt. Die Angabe der Spalten bei cut(1) entspricht der Angabe von Elementen bei mathematischen Mengen: Es gibt keine Reihenfolge, nur vorhanden oder nicht vorhanden.Nachtrag:
Leider ist cut wohl nicht in der Lage die Funktion von awk abzubilden. Der Aufruf von z.B.Code: Alles auswählen
cut -d" " -f3,1-4 file
gibt die Spalten jeweils nur einmal aus. Auch funktioniert die Umsortierung nicht.
Das rechtsbuendige Ausrichten wuerde ich als separates Problem angehen und als Filter einfach hinten an die Pipeline anhaengen.
Hier mal ein geschwind zusammen geschriebener Prototyp:
Code: Alles auswählen
awk '
{
x[NR]=$0
if (length($0)>max) {
max=length($0)
}
}
END {
for (l in x) {
printf("%*s\n", max, x[l])
}
}
'
Use ed once in a while!