-
BASH > awk
GENERALITES
awk OPTIONS BEGIN { ... } pattern { ... } pattern { ... } END { ... } fichier
Par défaut, chaque enregistrement est une ligne, chaque champs est séparé par un espace.
OPTIONS
awk -F’,‘change le séparateur de champs par une virgule (,). Si-F"", alors chaque caractère devient un champs.VARIABLES INTERNES
FS : séparateur de champs en entrée
FS peut être renseigné de deux manières :
awk -F ';' '...' fichier
ou
awk 'BEGIN {FS=";";}'
FS peut être de type "simple caractère" ou de type "RegEx" et peut changer à tout instant.
OFS : séparateur de champs en sortie
Par défaut, OFS est un espace. La virgule
,est le symbole de concaténation. Ainsi,,prendra la valeur de OFS :awk -F':' '{print $3,$4;}' fichier 41 41 100 101 112 119
awk -F':' 'BEGIN{OFS="=";} {print $3,$4;}' fichier 41=41 100=101 112=119
RS : séparateur d’enregistremenr (Record Separator)
Par défaut, RS est le saut de ligne. Exemple avec le fichier
fich: Enregistrements séparés par deux\n, et Champs séparés par un\n:toto A a tata B b
Essayons le script :
awk 'BEGIN { RS="\n\n"; FS="\n"; } { print $1,$2; }' fich toto A tata B titi C
ORS : Séparateur d’enregistrement en sotie (Output Record Separator)
Par défaut, ORS est le saut de ligne. Chaque enregistrement sera séparé par un
=en sortie :awk 'BEGIN{ORS="=";} {print;}' fichier toto A a=tata B b=titi C c=
NR : Nombre d’enregistrements (Number of Records)
Donne le numéro de l’enregistrement. Donc dans END :
awk '{print "record : ",NR;}END {print NR, "records au total";}' fichier record : 1 record : 2 record : 3 3 records au total
NF : Nombre de champs dans un enregistrement (Number of Fields)
toto A B C D tata A B C titi A B C D
awk '{print NR,"->",NF}' fich 1 -> 5 2 -> 4 3 -> 5
FILENAME : Nom du fichier d’entrée courant
FILENAME renvoie le nom du fichier en cours de traitement.
awk '{print FILENAME}' fichier fichier fichier fichier
FNR : Nombre d’enregistrements lus dans un fichier
FNRnombre d’enregistrements lus dans un fichier (remis à zéro à chaque nouveau fichier)$ awk '{print FILENAME, FNR;}' fich1 fich2 fich1 1 fich1 2 fich1 3 fich2 1 fich2 2 fich2 3
$0 $1 $2 $3 …
$0l’enregistrement entier$1premier champs$2deuxième champs$NFle dernier champs de l’enregistrement en coursARGC/ARGVnombre d’arguments / valeur des argumentsPATTERN
pattern { … }→ exécute…sipatternrenvoie true/Toto/si la chaine Toto est trouvée dans l’enregistrement en cours!/Toto/si la chaine Toto n’est pas trouvée dans l’enregistrement en cours!(/toto/ || /^tata/)si ne contient pas toto ou ne commence pas par tata/foo|bar/si foo ou bar sont trouvés dans l’enregistrement en cours/hel+o/si he + l (1 ou plus) + o sont trouvés (helo, hello, hellllllo, etc.)/to*to/tto ou toto ou toooooooto/t[oi]/o ou i (t, ti, to)$3 > 0si $3 est strictement plus grand que 0$2 >= 5si $2 est plus grand ou égal à 5$2 * $5 > 33→ si $2 multiplié par $5 est plus grand que 33$1 == "toto"→ si le champs $1 est toto$2 >= 4 || $3 <=20→ siNF != 3→ si le nombre de champs n’est pas égal à 3length($2) > 10→ si $2 a plus de 10 caractères$2~/^toto$/→ si $2 contient exactement toto (ni plus ni moins)NR==1 , NR==5→ du 1er au 5ème enregistrementMANIPULATION DU TEXTE
Remplacer du texte
sub( regex , remp , chaine )
Remplace la PREMIÈRE et la plus longue occurrence de
regexparrempdans la chainechaine.gsub( regex , rep , chaine )
Remplace TOUTES les occurrences. (g pour global).
Exemple : Remplacer tous les
#en_sur le champ$1.awk '{ gsub(/#/,"_",$1) ; print}' fichierPour récupérer la regex (
&) :awk ‘{ sub(/toto/, "& et tata"); print }’→ Remplace le premiertotopartoto et tatade chaque ligne.Autre exemple avec la chaine "
daabaaa" :sub(/a*/, "-&-", str) → d-aa-baa gsub(/a*/, "-&-", str) → d-aa-b-aa-
Pour supprimer l’effet du
&, il faut le double backslashé :\\&awk '{ sub(/\|/, "\\&"); print }'
Couper une chaine
substr( chaine, début, longueur ) substr("abcdefghij", 5, 3) efg
NµOTE : La chaine commence à
1.Si
longest absent : renvoie jusqu’à la fin de la chaine :substr("abcdefghij", 5) → efghij
Chercher une chaine
index( chaine , regex )
Retourne la position de la première occurrence de
regexdanschaine.note : La chaine commence à
1.awk ‘BEGIN { print index("foobar", "bar") }’→4Si rien de trouvé, renvoie
0.match( chaine , regex )
Cherche la plus longue
regexdanschaine.Retourne la position, sinon retourne
0.note : La chaine commence à
1.awk '{ endroit = match($0, regex) if (endroit) print "Trouvé ", regex, " à endroit ", endroit, " dans ", $0 }' fichier
EXEMPLE : chercher les mots commençant par sa dans la deuxième colonne :
awk '$2 ~ /^sa/' fichier
Pour faire l’inverse :
!avant la tilde~:awk '$2 !~ /^sa/' fichier
Plusieurs conditions :
awk '$2 !~ /^sa/ && $1 < 5' favorite_food.txt
ET :
&&. En fait, si condition1 est TRUE, alors on vérifie condition2.Majuscule - Minuscule
toupper($2)→ capitalise le champs $2tolower($2)→ minimalise le champs $2Concaténation
chaine = chaine $1″"→ concatène chaineLongueur de la chaine
length($2)
Présentation du texte
sprintf(format, expression1,...)
Transforme la présentation du texte comme le ferait
printfsprintf("pi = %.2f (env.)", 22/7)→ pi = 3.14 (env.)FONCTIONS
Tests
if ( TEST ) blabla else blibli→ si TEST renvoie true, alors blabla, sinon blibliCalculer le nombre d’enregistrements qui matchent
/toto/ { total++ } END { print total }
Splitter un champ en tableau
split( chaine, tableau, motif )
La
CHAINEsera divisée en éléments séparés par unMOTIFet envoyés dans unTABLEAU.Le premier élément du tableau est
tableau[1].MOTIF peut être une RegEx. Si MOTIF est absent, la valeur de FS est utilisée.
split retourne le nombre d’éléments créés.
RECORD le plus long
lenghth($0) > total { total = length($0) ; ligne = $0 } END { print total, ligne }
$3 le plus grand
$3 > max { max = $3 ; ligne = $0 } END { print max, ligne }
Inverser les FIELDS
{ for ( i = NF ; i > 0 ; i++ ) printf("%s", $i) ; printf("\n") }
Inverser l’ordre des RECORDS
{ ligne[NR] = $0 } END { i = NR while ( i > 0 ){ print ligne[i] i = i - 1 } }
Somme de tous les FIELDS sauf le 1er
{ somme = 0 ; for ( i = 2 ; i <= NF ; i = i + 1 ) somme = somme + $i ; print somme }
Compter le nombre de fois qu’une valeur apparaît dans un champ donné
awk '{ tab[$3]++ } END { for (i in tab) print i , " est apparu " , tab[i] , " fois." }'
tabest le tableau qui va prendre pour indice la valeur du champ$3(par exemple)Donc, on incrémente l’élément d’indice de même valeur que le champ.
Nombre aléatoire
rand()retourne un nombre entre 0 et 1 (non inclus).srand()pour avoir un vrai nombre aléatoire à chaque démarrage du script.Pour avoir un nombre entier entre
0etX:int(X * rand())
Nombre entier
int(X)Retourne l’entier deXle plus proche de zéro.int(3.9) 3 int(-3.9) -3
BEGIN et END
BEGIN: avant que le fichier ne soit analysé -END: après que le fichier soit analysé - BEGIN et END servent à afficher certaines infos :sudo awk ' BEGIN { FS=":" ; print "1\t\t2\t\t3\n" ; } {print $1,"\t\t",$2,"\t\t",$3;} END { print "-FIN-" } ' fichier 1 2 3 toto A a tata B b titi C c -FIN-
Envoyer une variable du shell dans awk
variable="ligne une\nligne deux" awk -v var="$variable" 'BEGIN {print var}' ligne une ligne deux
———-
https://www.thegeekstuff.com/tag/awk-tutorial-examples/
—
Afficher tout sauf la 1ère colonne :
awk '{$1=""; print $0}' somefile
Afficher tout sauf les deux premières colonnes :
awk '{$1=$2=""; print $0}' somefile
Afficher la deuxième colonne de la dernière ligne :
awk 'END {print $2}'
QUELQUES LIGNES DE CODES
awk -F"\t" '$4 != "" && $5 == ""' rain0 | wc -l
awk -F"\t" '$4 != "" && $5 == "" {print $4}' rain0 | sort | uniq -c
awk -F"\t" '$4 == "0.0" && $5 != "" {print $5}' rain0 | sort | uniq -c
awk 'BEGIN {FS=OFS="\t"} $4 == "0.0" && $5 == "" {$5=1} 1' rain0 > rain1
awk -F"\t" '$4 == "" && $5 != "" {print NR": "$0}' rain1
awk -F"\t" '$4 == ""' rain1 | wc -l
awk -F"\t" '$4 == "" {year[$1]++} END {for (i in year) print i"\t"year[i]}' rain1 | pr -t -3
awk -F"\t" '$1 >= 1916 && $1 <= 2015' rain1 > rain2
awk -F"\t" '$4 == "" {blanks++; next} $5 > 1 {print blanks,$5} {blanks = 0}' rain2 | sort -n | uniq -c
awk 'BEGIN {FS=OFS="\t"} {$4=""; $5=""} 1' rain2 > dummy
awk -F"\t" '($4 != "0.0" || $6 != "0.0") && $5 == 1 && $7 == 1' four_towns | cut -f4,6 > ulv-bur awk -F"\t" '{ulv+=$1; bur+=$2} END {printf ("%s%s%s%0.2f\n", "Burnie factor for ",NR," days is ",ulv/bur)}' ulv-bur
awk -F"\t" 'NR > 1 && $5 >= 1' accums | wc -l awk -F"\t" 'NR > 1 && $5 == 2' accums | wc -l
awk 'BEGIN {FS=OFS="\t"} {print $1"-"$2"-"$3,$4}' backfills > BFtrick awk 'BEGIN {FS=OFS="\t"} {print $1"-"$2"-"$3,$4,$5,$6,$7,$8,$9,$10,$11}' four_towns > FTtrick
awk 'BEGIN {FS=OFS="\t"} FNR==NR {backfill[$1]=$2; next} $1 in backfill {$2=backfill[$1]; $3="estBF"} 1' BFtrick FTtrick | sed 's/-/\t/g' > four_towns_backfilled
awk -F"\t" 'BEGIN {FS=OFS="\t"} $1 == 1994 && $2 == 11 && $3 == 28 {$4 = "2.0"; $5 = "estIF"} 1' four_towns_backfilled > four_towns_backfilled_infill grep -C51994$'\t'11$'\t'28 four_towns_backfilled_infill
awk 'BEGIN {FS=OFS="\t"} $4 == "" {for (i=7;i<=NF;i+=2) if ($i==1) ones++; \ if ($7 == 1) a=($6*1.02); if ($9 == 1) b=($8*1.02); if ($11 == 1) c=($10*1.21); \ $4=sprintf("%0.1f",(a+b+c)/ones); $5="estIF"; print; ones=a=b=c=0; next} \ {print}' four_towns_backfilled_infill > four_towns_backfilled_infilled
AWK here searches for lines with the Ulverstone total field (4) blank. When it finds such a line, it carries out the actions within the first set of curly braces, beginning with "for (1=7)" and ending with "next". That "next" makes AWK move to the next line and start again. If the next line has a non-blank Ulverstone total, the action in the next set of curly braces is carried out, namely "print" the line.
Back to the first set of actions. First, AWK counts up the number of 1-day totals available, as before, and stores the number in "ones". Next, it checks the Burnie, Latrobe and Northdown period fields (7, 9 and 11). If the period is 1, AWK stores the adjusted total (in fields 6, 8 or 10, multiplied by the appropriate adjustment factors) in a variable ("a" for Burnie, "b" for Latrobe, "c" for Northdown). AWK now replaces the blank field 4 with the average of the available, adjusted 1-day totals at the other stations, printing the average to the nearest 0.1 mm with sprintf. Field 5 (period) is then replaced with "estIF". Note that if "a", "b" or "c" doesn’t exist because there was no 1-day total at that station on that date, then AWK treats the variable as zero in calculating the average. After printing the line, the four variables are all re-set to zero.
REMPLACER DU TEXTE
awk '{ a=gensub(/.*#([0-9]+)(\").*/,"\\1","g",$0); if(a~/[0-9]+/) {gsub(/[0-9]+\"/,a+11"\"",$0);}print $0}' fichier
UPDATE
awk 'BEGIN{FS=OFS="\" \"#"}{if(NF<2){print;next;} a=gensub(/.* ([0-9]+)$/,"\\1","g",$1); b=gensub(/([0-9]+)\"/,"\\1","g",$2); gsub(/[0-9]+$/,a+11,$1); gsub(/^[0-9]+/,b+11,$2); print $1,$2 }' yourFile
gensub(regexp, replacement, how [, target]) # Search the target string target for matches of the regular expression regexp. If "how" is a string beginning with ‘g’ or ‘G’ (short for “global”), then replace all matches of regexp with replacement.
récupérerune expression
awk '{ r = gensub(/a(b*)c/, "Blabla: \\1", "g"); print r; }'
COMMANDES SYSTEMES ET VARIABLES
awk '{system("wc "$1)}' myfile
ECRIRE DIRECTEMENT DANS UN FICHIER
A la manière de
sed -i
:gawk -i inplace '{ gsub(/foo/, "bar") }; { print }' fichier
Pour créer une archive :
gawk -i inplace -v INPLACE_SUFFIX=.bak '{ gsub(/foo/, "bar") } { print }' fichier
—