AWK
Aus WS64 Wiki
(Unterschied zwischen Versionen)
WS64 (Diskussion | Beiträge) K |
WS64 (Diskussion | Beiträge) K |
||
Zeile 170: | Zeile 170: | ||
Aufruf: awk -v von="," -v nach="|" -f csv.awk datei.csv | Aufruf: awk -v von="," -v nach="|" -f csv.awk datei.csv | ||
Todo: Abfangen von Zeilenumbrüchen | Todo: Abfangen von Zeilenumbrüchen | ||
+ | |||
+ | |||
+ | Weiter Beispiele: | ||
+ | <pre> | ||
+ | # das letzte Feld jeder Eingabezeile ausgeben | ||
+ | awk '{ print $NF }' /etc/hosts | ||
+ | |||
+ | # die 10. Eingabezeile ausgeben | ||
+ | awk 'NR == 10' /etc/passwd | ||
+ | |||
+ | # alle Zeilen ausgeben, die entweder "root" oder "false" enthalten | ||
+ | # (also Suche wie bei egrep) | ||
+ | awk '/root|false/' /etc/passwd | ||
+ | |||
+ | # Gesamtzahl der Eingabe-Zeilen ausgeben | ||
+ | awk 'END { print NR }' /etc/passwd | ||
+ | |||
+ | # das erste und letzte Feld der Eingabezeilen 5 bis 10 ausgeben | ||
+ | awk -F: 'NR == 5, NR == 10 { print $1, $NF }' /etc/passwd | ||
+ | |||
+ | # das erste und vorletzte Feld der letzten Eingabezeile ausgeben | ||
+ | awk -F: 'END { print $1, $(NF-1) }' /etc/passwd | ||
+ | |||
+ | # passwd-Eintrag für die aktuelle UID ausgeben | ||
+ | awk -F: "\$3 == $UID" /etc/passwd | ||
+ | awk -F: -v uid=$UID '$3 == uid' /etc/passwd | ||
+ | |||
+ | # Ausgabe von Zeilen mit mehr als 2 Feldern | ||
+ | awk 'NF > 2' /etc/hosts | ||
+ | |||
+ | # Ausgabe von Zeilen, deren Feld 3 kleiner als 50 ist | ||
+ | awk -F: '$3 < 50' /etc/passwd | ||
+ | |||
+ | # Ausgabe von Zeilen, deren letztes Feld "false" enthält | ||
+ | awk -F: '$NF ~ /false/' /etc/passwd | ||
+ | |||
+ | # Ausgabe der Anzahl von Zeilen, deren letztes Feld "false" enthält; | ||
+ | # Anmerkung: das Semikolon vor END ist nicht nötig | ||
+ | awk -F: '$NF ~ /false/ { anz++ } ; END { print anz }' /etc/passwd | ||
+ | |||
+ | # Ausgabe von nicht leeren Zeilen; | ||
+ | # NF wird hier im Booleschen Kontext ausgewertet (0 ist FALSE, der Rest TRUE) | ||
+ | awk NF /etc/hosts | ||
+ | |||
+ | # ermittle, wie oft jeder Wert des letzten Feldes der Eingabezeilen vorkommt | ||
+ | awk -F: ' | ||
+ | { ANZ[$NF]++ } | ||
+ | END { for (w in ANZ) printf("%s: %d\n", w, ANZ[w]) } | ||
+ | ' /etc/passwd | ||
+ | |||
+ | # tausche Feld 1 und 2 der ersten 10 Eingabezeilen; gib die restlichen Zeilen | ||
+ | # unverändert aus; für die Ausgabe nutzen wir eine Regel, die nur aus dem | ||
+ | # Muster 1 (also TRUE) besteht und deren Aktion dann print lautet | ||
+ | awk -F: ' | ||
+ | BEGIN { OFS = FS } | ||
+ | NR < 11 { t = $1; $1 = $2; $2 = t } | ||
+ | 1 | ||
+ | ' /etc/passwd | ||
+ | |||
+ | # ermittle die längste Eingabe-Zeile | ||
+ | awk ' | ||
+ | length($0) > max { max = length($0) ; fn = FILENAME ; fnr = FNR ; line = $0 } | ||
+ | END { if (fnr) printf("%d Zeichen in Zeile %d in Datei %s\n%s\n", max, fnr, fn, line) } | ||
+ | ' /etc/{hosts,passwd} | ||
+ | |||
+ | # gib die UIDs der Nutzer, die die bash als Login-Shell haben, fallend sortiert | ||
+ | # aus; anschließend wird noch die Anzahl dieser Nutzer ausgegeben | ||
+ | awk -F: ' | ||
+ | BEGIN { sort = "sort -rn" } | ||
+ | $7 ~ /bash/ { print $3 | sort ; anz++ } | ||
+ | END { close(sort) ; printf("Anzahl: %d\n", anz) } | ||
+ | ' /etc/passwd | ||
+ | |||
+ | # Einrücken der Inhalte von HTML-Absätzen; | ||
+ | # Annahme: <p> und </p> stehen jeweils auf getrennten Zeilen und sollen selbst | ||
+ | # nicht mit eingerückt werden | ||
+ | awk '/<p>/, /<\/p>/ {if ($0 !~ /<\/?p>/) {print " " $0; next}}; 1' p.html | ||
+ | |||
+ | # alternativ funktioniert das auch ohne "next", indem die erste Regel, deren | ||
+ | # Muster einen Bereich spezifiziert, nur 2 Leerzeichen als Präfix der | ||
+ | # Einrückung ausgibt, wogegen der Zeileninhalt dann von der zweiten Regel | ||
+ | # ausgegeben wird, die auch der Ausgabe der nicht eingerückten Zeilen außerhalb | ||
+ | # der Bereiche dient | ||
+ | awk '/<p>/, /<\/p>/ {if ($0 !~ /<\/?p>/) {printf(" ")}}; 1' p.html | ||
+ | |||
+ | # die Auswahl von Bereichen kann auch durch eigene Statusvariablen erfolgen | ||
+ | awk ' | ||
+ | /<p>/ { in_p = 1; print; next } | ||
+ | /<\/p>/ { in_p = 0; print; next } | ||
+ | in_p { print " " $0; next} | ||
+ | 1 | ||
+ | ' p.html | ||
+ | |||
+ | # obige Regeln kann man kürzer formulieren, wenn man sie geeignet anordnet, so | ||
+ | # dass je nach Datenkonstellation die richtige Aktion erfolgt | ||
+ | awk ' | ||
+ | /<\/p>/ { in_p = 0 } | ||
+ | in_p { printf(" ") } | ||
+ | /<p>/ { in_p = 1 } | ||
+ | 1 | ||
+ | ' p.html | ||
+ | </pre> |
Aktuelle Version vom 30. März 2021, 12:21 Uhr
Invoking Awk: awk [-F<ch>] {pgm} | {-f <pgm file>} [<vars>] [-|<data file>] -- where: ch: Field-separator character. pgm: Awk command-line program. pgm file: File containing an Awk program. vars: Awk variable initializations. data file: Input data file.
AWK Library # PATH Variables, each in a new line, headline separated: path | awk "{str=$0;gsub(\";\",\"\n\",str);sub(\"=\",\"\n\n\",str);print str}" # gsub: alle Vorkommen von ; durch Zeilenumbruch. sub: erstes Vorkommen von = durch 2 Zeilenumbrüche ersetzen # Leerzeilen weg awk "NF>0" 1.txt # doppelte aufeinanderfolgende Zeilen raus awk "{if (a!=$0) {print $0};a=$0}" 1.TXT # Anzahl Zeilen awk "END { print NR \" lines\" }" 1.TXT # Anzahl Wörter awk "{ nw += NF } END { print nw \" words\"}" 1.TXT # Anzahl Buchstaben awk "{ nc += length($0) } END { print nc \" chars\" }" 1.TXT # Anzahlen awk "{ nw += NF;nc += length($0);if (NF==0) e++;} END { print \"\nFile : \" FILENAME \"\nLines: \" NR \" (empty: \" e+0 \")\nWords: \" nw \"\nChars: \" nc}" 1.TXT # Erzeuge Copy-Befehl, der den Dateinamen durch den Verzeichnispfad ersetzt dir /b /s *.bat | awk -v wobinich=%cd:\=/% -F\ "BEGIN {print \"REM Copy Filename to last Directoryname\";a=\"\x22\";bs=\"\x5c\";b=\" \";split(wobinich,ar,\"/\");start=length(ar)}{split($NF,ex,\".\");t=$(start);s=$(start);for (i=start+1;i<NF;i++){t=t bs $i;s=s \"_\" $i};print \"copy \"a $0 a b a t bs s \".\" ex[length(ex)] a}" # Hänge allen Files in CSV noch ein Semikolon plus Dateinamen (ohne Extension) an awk.exe -F; "$1!~/CWID/ {print $0\";\"substr(substr(FILENAME,1,length(FILENAME)-4),5)}" csv\*.csv > All.csv # der innere substr entfernt die Extension, der äussere das 3stellige Verzeichnis (CSV) vorne #Nummeriere Textfile, aber nicht die Leerzeilen NF {c=++a;printf ("%5d: %s\n",c,$0)} NF==0 #Sortieren und doppelte Zeilen raus (Leerzeilen auch) NF {a[$0]=1} END {for (i=1;i<asorti(a,b);i++)print b[i];printf b[i]} #ungeordnet (durcheinander!) plus Leerzeile, aber schneller (7MB/12000DS: ~3 min sortiert, <1 sek unsortiert): NF {a[$0]=1} END {for (w in a) print w} #nur Zeilen die suchtext enthalten awk "/suchtext/"
#insert before or after other files BAT: @echo off cls set search="export LC_ALL=\"en_US.UTF-8\"" set insertbefore= set insertafter="mount -r /dev/mmcblk0p5 /mnt/ws" copy koreader.sh koreader.sh_backup awk -v search=%search% -v insertbefore=%insertbefore% -v insertafter=%insertafter% -f patch.awk koreader.sh_backup > koreader.sh dos2unix -U koreader.sh set search=" self.pageturn_count = self.pageturn_count + 1" set insertbefore="os.execute(\"hwclock -s -u\")" set insertafter= copy plugins\statistics.koplugin\main.lua plugins\statistics.koplugin\main.lua_backup awk -v search=%search% -v insertbefore=%insertbefore% -v insertafter=%insertafter% -f patch.awk plugins\statistics.koplugin\main.lua_backup > plugins\statistics.koplugin\main.lua dos2unix -U plugins\statistics.koplugin\main.lua AWK: BEGIN { i=0 foundafter=0 } { n++ a[n]=$0 if (foundafter==1){ if (a[n]!=insertafter) { a[n]=insertafter n++ a[n]=$0 } } if (a[n]==search) { if (insertafter>"" && foundafter==0) { foundafter=1 } else foundafter=0 if (insertbefore>"") { if (a[n-1]!=insertbefore) { a[n+1]=a[n] a[n]=insertbefore n++ } } } else foundafter=0 } END { for (i=1;i<=n;i++) print a[i] }
@echo off echo @echo off > backslash2slash.bat echo awk "{a=$0;sub(/\\/,\"/\",a);print a}" %%1 ^> %%2 >> backslash2slash.bat echo @echo off > make_Apple_m3us_copy.bat dir /b /s _all.m3u | awk -v wobinich=%cd:\=/% -F\ "BEGIN {print \"REM Copy Filename to last Directoryname\";a=\"\x22\";bs=\"\x5c\";b=\" \";sl=\"\x2f\";nl=\"\x3e\" \"\x6e\" \"\x75\" \"\x6c\";split(wobinich,ar,\"/\");start=length(ar)+1}{split($NF,ex,\".\");t=$(start);s=$(start);for (i=start+1;i<NF;i++){t=t bs $i;s=s \"_\" $i};quelle=a $0 a;ziel=a t bs s \".\" ex[length(ex)] a;gsub(/&/,\"and\",t);print \"echo \"t;print \"call backslash2slash.bat \" quelle b ziel}">> make_Apple_m3us_copy.bat call make_Apple_m3us_copy.bat del make_Apple_m3us_copy.bat del backslash2slash.bat
Trim Funktion:
function ltrim(s) { sub(/^[ \t\r\n]+/, "", s); return s } function rtrim(s) { sub(/[ \t\r\n]+$/, "", s); return s } function trim(s) { return rtrim(ltrim(s)); } BEGIN { # whatever } { # whatever } END { # whatever }
CSV:
{ n=split($0,a,von) for (i=1;i<=n;i++) { if (substr(a[i],1,1)=="\x22" && substr(a[i],length(a[i]))!="\x22") { a[i]=a[i] von a[i+1] for (j=i+1;j<n;j++) a[j]=a[j+1] a[n]="" n=n-1 i=i-1 } } s="" for (i=1;i<=n;i++) { if (substr(a[i],1,1)=="\x22") a[i]=substr(a[i],2,length(a[i])-2) s=s a[i] nach } print substr(s,1,length(s)-1) }
Aufruf: awk -v von="," -v nach="|" -f csv.awk datei.csv Todo: Abfangen von Zeilenumbrüchen
Weiter Beispiele:
# das letzte Feld jeder Eingabezeile ausgeben awk '{ print $NF }' /etc/hosts # die 10. Eingabezeile ausgeben awk 'NR == 10' /etc/passwd # alle Zeilen ausgeben, die entweder "root" oder "false" enthalten # (also Suche wie bei egrep) awk '/root|false/' /etc/passwd # Gesamtzahl der Eingabe-Zeilen ausgeben awk 'END { print NR }' /etc/passwd # das erste und letzte Feld der Eingabezeilen 5 bis 10 ausgeben awk -F: 'NR == 5, NR == 10 { print $1, $NF }' /etc/passwd # das erste und vorletzte Feld der letzten Eingabezeile ausgeben awk -F: 'END { print $1, $(NF-1) }' /etc/passwd # passwd-Eintrag für die aktuelle UID ausgeben awk -F: "\$3 == $UID" /etc/passwd awk -F: -v uid=$UID '$3 == uid' /etc/passwd # Ausgabe von Zeilen mit mehr als 2 Feldern awk 'NF > 2' /etc/hosts # Ausgabe von Zeilen, deren Feld 3 kleiner als 50 ist awk -F: '$3 < 50' /etc/passwd # Ausgabe von Zeilen, deren letztes Feld "false" enthält awk -F: '$NF ~ /false/' /etc/passwd # Ausgabe der Anzahl von Zeilen, deren letztes Feld "false" enthält; # Anmerkung: das Semikolon vor END ist nicht nötig awk -F: '$NF ~ /false/ { anz++ } ; END { print anz }' /etc/passwd # Ausgabe von nicht leeren Zeilen; # NF wird hier im Booleschen Kontext ausgewertet (0 ist FALSE, der Rest TRUE) awk NF /etc/hosts # ermittle, wie oft jeder Wert des letzten Feldes der Eingabezeilen vorkommt awk -F: ' { ANZ[$NF]++ } END { for (w in ANZ) printf("%s: %d\n", w, ANZ[w]) } ' /etc/passwd # tausche Feld 1 und 2 der ersten 10 Eingabezeilen; gib die restlichen Zeilen # unverändert aus; für die Ausgabe nutzen wir eine Regel, die nur aus dem # Muster 1 (also TRUE) besteht und deren Aktion dann print lautet awk -F: ' BEGIN { OFS = FS } NR < 11 { t = $1; $1 = $2; $2 = t } 1 ' /etc/passwd # ermittle die längste Eingabe-Zeile awk ' length($0) > max { max = length($0) ; fn = FILENAME ; fnr = FNR ; line = $0 } END { if (fnr) printf("%d Zeichen in Zeile %d in Datei %s\n%s\n", max, fnr, fn, line) } ' /etc/{hosts,passwd} # gib die UIDs der Nutzer, die die bash als Login-Shell haben, fallend sortiert # aus; anschließend wird noch die Anzahl dieser Nutzer ausgegeben awk -F: ' BEGIN { sort = "sort -rn" } $7 ~ /bash/ { print $3 | sort ; anz++ } END { close(sort) ; printf("Anzahl: %d\n", anz) } ' /etc/passwd # Einrücken der Inhalte von HTML-Absätzen; # Annahme: <p> und </p> stehen jeweils auf getrennten Zeilen und sollen selbst # nicht mit eingerückt werden awk '/<p>/, /<\/p>/ {if ($0 !~ /<\/?p>/) {print " " $0; next}}; 1' p.html # alternativ funktioniert das auch ohne "next", indem die erste Regel, deren # Muster einen Bereich spezifiziert, nur 2 Leerzeichen als Präfix der # Einrückung ausgibt, wogegen der Zeileninhalt dann von der zweiten Regel # ausgegeben wird, die auch der Ausgabe der nicht eingerückten Zeilen außerhalb # der Bereiche dient awk '/<p>/, /<\/p>/ {if ($0 !~ /<\/?p>/) {printf(" ")}}; 1' p.html # die Auswahl von Bereichen kann auch durch eigene Statusvariablen erfolgen awk ' /<p>/ { in_p = 1; print; next } /<\/p>/ { in_p = 0; print; next } in_p { print " " $0; next} 1 ' p.html # obige Regeln kann man kürzer formulieren, wenn man sie geeignet anordnet, so # dass je nach Datenkonstellation die richtige Aktion erfolgt awk ' /<\/p>/ { in_p = 0 } in_p { printf(" ") } /<p>/ { in_p = 1 } 1 ' p.html