AWK: Abkürzung, die aus den Anfangsbuchstaben der Nachnamen der drei "Väter" der Sprache AWK besteht: Al Aho, Peter Weinberger, Brian Kernighan
> echo -e "1\n2\n3"
1
2
3
> echo -e "1\n2\n3" | awk 'NR==2'
2
> echo "1 2 3" | awk '{print $2}'
2
> echo "1:2:3" | awk -F':' '{print $2}'
2
> echo "foooobazbarrrrr" | awk '{print $1}'
foooobazbarrrrr
> echo "foooobazbarrrrr" | awk '{ match($0, /(fo+).+(bar*)/, arr); print arr[1], arr[2] }'
foooo barrrrr
echtes runden mit awk:
> echo "5.56" | awk '{printf "%.1f\n", $1}'
5.6
> echo "5.56" | awk '{printf "%.0f\n", $1}'
6
abrunden mit awk:
> echo "5.56" | awk '{printf("%u\n", $1)}'
5
Zahlen mit fester Länge ausgeben:
> echo "5.56" | awk '{printf("%.8u\n", $1)}'
00000005
> echo | awk '{print 4 * atan2(1,1)}'
3.14159
# "AWK" ist nur bis zur 15. Nachkommastelle genau
> echo | awk '{printf "%.15f\n", 4 * atan2(1,1)}'
3.141592653589793
Zusammenzählen aller Werte in der 1. Spalte ("$1"):
# awk '{zwischenwert=$1;summe+=zwischenwert}END{print "Gesamtwert:",summe}'
# awk '{zwischenwert=$1; summe += zwischenwert } END { print "Gesamtwert:", summe }'
# awk '{zwischenwert=$1; summe += zwischenwert } END { printf("%li", summe)}'
# awk '{z=$1;s+=z}END{printf("%li", s)}'
# awk '{z=$1;s+=z}END{print s}'
# awk '{z=$1;s+=z}END{printf("%.2f\n",s/1024^3)}'
Durchschnitt aller Werte der letzten Spalte:
# cat ... | nl | awk '{ zwischenwert=$NF; summe += zwischenwert } END { print summe/$1 }'
# echo "7" | awk '{for (i=1;i<=$1;i++) print i }'
1
2
3
4
5
6
7
Wurzel aus 9
> echo "9" | awk '{print sqrt($1)}'
3
> echo "10 1" | awk '{print sqrt($1-$2)}'
3
5. Wurzel aus 4 (https://frageit.de/questions/42775094/nth-root-in-bash):
> awk 'BEGIN { print (4 ** (1.0 / 5)) }'
1.31951
> awk 'BEGIN { print (ARGV[2] ** (1.0 / ARGV[1])) }' 5 4
1.31951
natürlicher Logarithmus aus 5:
> echo "5" | awk '{print log($1)}'
1.60944
natürlicher Logarithmus aus 20:
> echo "20" | awk '{print log($1)}'
2.99573
dezimaler Logarithmus 1000:
> echo "1000" | awk '{print log($1)/log(10)}'
3
binärer Logarithmus aus 8:
> echo "8" | awk '{print log($1)/log(2)}'
3
Mit Alphanumerischen Zeichen:
# echo 'WPA2' | awk '{proto="nix"; if ($1 == "WPA") proto="WPA"; if ($1 == "WPA2") proto="RSN"; print proto}'
RSN
die "if"-Anweisung von AWK kann sogar mit Kommastellen umgehen:
# echo "1.5" | awk '{if ($1 < 3) GR="gross" ; if ($1 < 2) GR="mittel" ; if ($1 < 1) GR="klein" ; print $1"="GR}'
1.5=mittel
# echo "1.5" | awk '{if ($1 < 3) GR=3 ; if ($1 < 2) GR=2 ; if ($1 < 1) GR=1 ; print GR}'
2
# echo "2" | awk '{if ($1 == 1) GR="klein" ; if ($1 == 2) GR="mittel" ; if ($1 == 3) GR="gross" ; print GR}'
mittel
# vi ip2int.sh
#!/bin/bash
echo "${1}" | awk -F'.' '{print $1"\n"$2"\n"$3"\n"$4}' | nl | while read N Z
do
echo "${N} ${Z}" | awk '{lfdn=$1 ; if (lfdn == 1) f='256*256*256' ; if (lfdn == 2) f='256*256' ; if (lfdn == 3) f=256 ; if (lfdn == 4) f=1 ; print f*$2}'
done | awk '{z=$1;s+=z}END{print s}'
# /bin/bash ip2int.sh 192.168.1.100 3232235876 # /bin/bash ip2int.sh 255.255.255.0 4294967040
# echo "$1" | awk '{for (i=0; $1>=2^i; i++); i--; Z=2^i} END {print i,Z}'
exit
# solange die erste Zahl >=0 ist, weitermachen:
# /var/tmp/test2.sh 4294967040
31 2147483648
# echo "4294967040-2147483648"|bc -l
2147483392
# /var/tmp/test2.sh 2147483392
30 1073741824
Das mach ich später fertig, hab jetzt keine Zeit mehr…
c Ein ASCII-Zeichen.
Ist das entsprechende Argument eine Zahl,
so wird diese als Kode im Zeichensatz interpretiert und ausgegeben.
d Eine vorzeichenbehaftete Integerzahl
i Eine vorzeichenbehaftete ganze Zahl.
e Eine Gleitkommazahl der Form: [-]d.ddddddE[+-]dd
f Eine Gleitkommazahl der Form: [-]ddd.dddddd
g das Argument wird entweder wie e oder f umgewandelt.
Je nachdem, welches Ergebnis kürzer ist.
Nicht signifikante Nullen werden dabei unterdrückt.
o Eine vorzeichenlose Oktalzahl.
s Ein String.
u Eine vorzeichenlose ganze Zahl.
x Eine vorzeichenlose Hexadezimalzahl mit Kleinbuchstaben.
X Eine vorzeichenlose Hexadezimalzahl mit Großbuchstaben.
% Hebt die bedeutung von % auf. Also %% gibt % aus.
abs(x) Funktion zum ausgeben vom Absolutwert von x
int(x) Ganzzahliger Anteil von x
log(x) natürlicher Logarithmus von x
rand() Eine Zufallszahl z: 0 <= z < 0
sqrt(x) Wurzel aus x
# echo "10 50" | awk 'func abs(x) {return ((x < 0.0) ? -x : x)} {printf "%.0f\n", abs($1 - $2)}'
# echo "1021 576" | awk '{printf("%d %d\n",($1/($1/720))/2,($2/($1/768))/2)}'
# echo "1021 576" | awk '{printf("%i %i\n",($1/($1/720))/2,($2/($1/768))/2)}'
# echo "1021 576" | awk '{printf("%u %u\n",($1/($1/720))/2,($2/($1/768))/2)}'
# echo "1021 576" | awk '{printf("%uk\n",$1*$2*1000/69120)}'
Rechengenauigkeit
# echo "76.1 81.8 3.1415926535897932384626433832795028841971693993751" | awk '{print ($2/2)^2*$3*$1/1000}'
399.927
# echo "76.1 81.8 3.1415926535897932384626433832795028841971693993751" | awk '{OFMT="%.16G";print ($2/2)^2*$3*$1/1000}'
399.9273868814023
# echo "76.1 81.8 3.1415926535897932384626433832795028841971693993751" | awk '{OFMT="%.13f";print ($2/2)^2*$3*$1/1000}'
373,9770000000000
# echo "76.1 81.8 3.1415926535897932384626433832795028841971693993751" | awk '{OFMT="%.14f";print ($2/2)^2*$3*$1/1000}'
373,97699999999998
# echo "76.1 81.8 3.1415926535897932384626433832795028841971693993751" | awk '{OFMT="%.23G";print ($2/2)^2*$3*$1/1000}'
399.92738688140229896817
# echo "(81.8/2)^2 * 3.1415926535897932384626433832795028841971693993751 * 76.1 / 1000" | bc -l
399.92738688140234827240
Aus einer Datei soll die letzte Spalte von allen Zeilen ausgegeben werden, die "78378" aber nicht "sftp" enthalten:
# export SUCHPATTERN="78378"
# awk '/'$SUCHPATTERN'/ && !/sftp/ {printf("%s ", $NF);}' [Datei]
# awk '/78378/ && !/sftp/ {printf("%s ", $NF);}' [Datei]
Es entspricht dem Aufruf:
# cat [Datei] | grep '78378' | grep -v 'sftp' | awk '{printf("%s ", $NF);}'
Die letzte Spalte an den Anfang setzen, egal wieviel Spalten die Zeile hat:
# awk '{ printf $NF;$NF = "" ;printf " "$0"\n" }'
Wenn die Spalte 4 groesser ist als Spalte 6 oder wenn in Spalte 7 eine Zahl steht, die groesser als 30000 ist, wird die Zeile ausgegeben:
# awk '$4 < $6 || $7 > 30000'
Es wird die Zeile ausgegeben, in der von Spalte 7, die Groesste Zahl steht:
# vi script.awk
max < $7 { max = $7 ; stadt = $1 }
END { print "Die meisten Zuschauer waren in",stadt,"("max")." }
# awk -v max=0 -f script.awk
mit AWK alles in Großbuschtaben umwandeln:
# echo "buchstaben" | awk '{print toupper($0)}'
BUCHSTABEN
mit AWK alles in Kleinbuschtaben umwandeln:
# echo "BUCHSTABEN" | awk '{print tolower($0)}'
buchstaben
AWK als grep:
# awk '/PATERN/' # alle Zeilen mit "PATTERN"
# awk '/^[0-9]+/ {print $1}' # das erste Wort aller Zeilen mit einer Ziffer am Anfang
# awk '/^[0-9]+|^#/' # alle Zeilen mit einer Ziffer oder "#" am Anfang
# awk '/[^n]{print $1}' # es werden nur Zeilen verarbeitet, in denen kein "n" vorkommt
# awk 'lenght() > 50 {print}' # nur Zeilen die laenger als 50 Zeichen sind
AWK als sed:
# awk '/Anfang/,/Ende/' # Textabschnitte von "Anfang" bis "Ende"
# awk -v neu="-" '{$2 = neu;print};' # zweite Spalte wird durch "-" ersetzt
# awk -v alt='_' -v neu='-' '{sub(alt, neu); print}' # einfache Ersetzung
# awk -v alt='_' -v neu='-' '{gsub(alt, neu); print}' # globale Ersetzung
# awk '{alt="_"; neu="-"} {gsub(alt, neu); print}' # globale Ersetzung
Beispiel:
# awk '{ alt="/"; neu=" "; gsub(alt, neu); $1; $2; $5$4$3; $6 print }'
Es sollen nur die Leerzeichen der Variablen (vor dem Gleichheitszeichen) gegen Unterstriche ausgetauscht werden, nicht jedoch die Leerzeichen der Werte (hinter dem Gleichheitszeichen). Dazu wird vor der Veränderung der Wert in eine Variable gespeichert:
# echo "CPU Signature=Type 0, Family 6, Model 26, Stepping 5" | awk -F'=' '{wert=$2 ; gsub(" ", "_") ; print $1"="wert}'
CPU_Signature=Type 0, Family 6, Model 26, Stepping 5
Und jetzt noch zusätzlich die Variablen von Großschreibung in Kleinschreibung umwandeln.
# echo "CPU Signature=Type 0, Family 6, Model 26, Stepping 5" | awk -F'=' '{wert=$2 ; gsub(" ", "_") ; variable=tolower($1) ; print variable"="wert}'
cpu_signature=Type 0, Family 6, Model 26, Stepping 5
Zeilenlängen einer Datei ermitteln
# wc -L [dateiname].csv
# awk '{print length;exit}' [dateiname].csv
78
CSV (comma separated version) in "feste Spaltenbreite" umwandeln
12 Zeichen breite Spalte generieren: "%12s"
# awk -F';' '{printf("%12s%9s%13s%14s%9s\n", $1,$2,$5,$6,$7)}' daten.txt
spalte1 spalte2 spalte5 spalte6 Spalte7
13 1 092007 01/31/2099 al
52 1 092009 08/31/2009 al
62 1 092009 08/31/2009 al
64 1 092009 08/31/2009 al
71 1 092009 08/31/2009 al
85 1 092009 08/31/2009 al
# Da wo das Komma steht, werden die Freiräume mit Leerzeichen # aufgefüllt.
# echo "Spalte01|Spalte02|Spalte03|Spalte4|Spalte5|Spalte6" | awk -F'|' '{printf ("%10s%16s%16s%16s%24s%21s\n", $1" | ",$2" | ",$3" | ",$4" | ",$5" | ",$6)}'
allerdings sind die Einträge in der ersten Spalte immer rechtsbündig:
> echo "innodb_file_per_table ON" | awk '{printf("%47s%47s\n",$1" = ",$2)}'
innodb_file_per_table = ON
will man sie linksbündig, dann kann man das so machen:
> echo "innodb_file_per_table ON" | rev | awk '{printf("%47s%47s\n",$1" = ",$2)}' | rev | sed 's/[ ]*$//'
innodb_file_per_table = ON
Muss man einen String innerhalb eines Stringes (Unterstring ⇒ SubString) zerlegen, also zum Beispiel ein Datum in einem Satz umformen, dann bietet sich die Funktion substr in AWK an:
echo "Das Datum 21.03.1969 im klassischen Format." | awk '{print $1,$2,substr($3,7,4)"-"substr($3,4,2)"-"substr($3,1,2),$4,"Euro-"$6}'
Das Datum 1969-03-21 im Euro-Format.
substr benötigt drei Parameter:
die ersten beiden Zeichen einer Zeichenkette ausgeben:
echo "${STRING}" | awk '{print substr($1,1,2)}'
die letzten beiden Zeichen einer Zeichenkette ausgeben:
echo "${STRING}" | awk '{a=length($1)-1; print substr($1,a,2)}'
—-
Will man zum Beispiel die Werte "cpu family", "model" und "stepping" einer CPU unter Linux auslesen, dann kann man einfach in dieser Datei nachsehen:
# cat /proc/cpuinfo processor : 0 vendor_id : GenuineIntel cpu family : 15 model : 2 model name : Intel(R) Pentium(R) 4 CPU 2.60GHz stepping : 9 cpu MHz : 2593.547 cache size : 512 KB fdiv_bug : no hlt_bug : no f00f_bug : no coma_bug : no fpu : yes fpu_exception : yes cpuid level : 2 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe up pebs bts cid xtpr bogomips : 5187.09 clflush size : 64 power management:
Hat diese CPU allerdings mehr als einen Kern, dann wird es schnell unübersichtlich:
# cat /proc/cpuinfo processor : 0 vendor_id : GenuineIntel cpu family : 6 model : 26 model name : Intel(R) Xeon(R) CPU X5570 @ 2.93GHz stepping : 5 cpu MHz : 2926.105 cache size : 8192 KB physical id : 1 siblings : 8 core id : 0 cpu cores : 4 apicid : 16 initial apicid : 16 fpu : yes fpu_exception : yes cpuid level : 11 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good xtopology pni dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm dca sse4_1 sse4_2 lahf_lm ida tpr_shadow vnmi flexpriority ept vpid bogomips : 5852.21 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: ... processor : 15 vendor_id : GenuineIntel cpu family : 6 model : 26 model name : Intel(R) Xeon(R) CPU X5570 @ 2.93GHz stepping : 5 cpu MHz : 2926.105 cache size : 8192 KB physical id : 0 siblings : 8 core id : 3 cpu cores : 4 apicid : 7 initial apicid : 7 fpu : yes fpu_exception : yes cpuid level : 11 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good xtopology pni dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm dca sse4_1 sse4_2 lahf_lm ida tpr_shadow vnmi flexpriority ept vpid bogomips : 5851.96 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management:
Die oben gezeigte Ausgabe stammt von einem Dual-Quad-Core mit Hyper-Threading. Also sind es nur zwei CPUs mit je vier Kernen, die über erweiterte Register verfühgt, wodurch der einzelne Kern zwischen zwei Pipes schneller hin und her springen kann.
Hyper-Threading bringt nur einen Geschwindigkeitsvorteil, wenn man mehr Prozesse laufen lassen möchte als sich CPU-Kerne im System befinden! An sonsten werden z.B. die ersten beiden Prozesse auf die ersten beiden virtuellen CPUs gestartet, wobei das aber der selbe Kern (mit Hyper-Threading) ist und alle anderen CPU-Kerne haben nix zu tun.
Deshalb sollte man HT (Hyper-Threading) im BIOS nur dann aktivieren, wenn man vilele Prozesse fährt.
Möchte man
dann kann man sich alles, bis zu der Zeile anzeigen lassen, in der "stepping" das erste mal vorkommt:
sed -e '/stepping/ q' /proc/cpuinfo processor : 0 vendor_id : GenuineIntel cpu family : 6 model : 26 model name : Intel(R) Xeon(R) CPU X5570 @ 2.93GHz stepping : 5
Das ist schon sehr viel übersichtlicher und enthält auch alle Informationen, die wir brauchen.
Allerdings werden auch da noch viele unnütze Infos angezeigt, die rausgefiltert werden sollen.
Filtert man jetzt nach der klassischen Art mit "grep", dann könnte das so aussehen:
# sed -e '/stepping/ q' /proc/cpuinfo | egrep 'cpu family|model|stepping' | fgrep -v 'model name' | awk '{print $NF}'
6
26
5
Das gleiche Ergebnis kann man allerdings auch bekommen, wenn man an Stelle von drei Prozessen (egrep, fgrep und awk) nur einen aufruft (awk):
# sed -e '/stepping/ q' /proc/cpuinfo | awk '/cpu family|model|stepping/ && !/model name/ {print $NF}'
6
26
5
Denn AWK kann alles, was grep kann.