User Tools

Site Tools


informatique:linux:awk

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
informatique:linux:awk [2010/04/28 14:50] – créée pteuinformatique:linux:awk [2022/04/13 13:03] (current) – [Exemples] N'afficher que les lignes impaires pteu
Line 1: Line 1:
-{{tag>langage programmation}} 
- 
- 
 ======awk====== ======awk======
  
-C'est une commande (un langagede manipulation de chaînes de caractères d'un fichier ou d'un flux en entrée.+C'est un langage de manipulation de chaînes de caractères d'un fichier ou d'un flux en entrée.
  
 Les différentes commandes que l'on peut passer sont de la forme **motif { action }**. Les différentes commandes que l'on peut passer sont de la forme **motif { action }**.
-''awk'' découpe le flux de caractère par ligne (enregistrement) et colonne (champ) ; on peut récupérer les colonnes avec $1, $2,..,$NF (dernière colonne) et $0 qui correspond à la ligne complète. Les champs peuvent etre specifiés par des expressions, comme $(NF-1) pour l'avant dernier champs.+**awk** traite séquentiellement le flux de caractères (fichier en paramètre ou flux en entrée) par ligne (enregistrement) et colonne (champ) ; on peut récupérer les colonnes avec les variables $1, $2, .., $10 ,$NF (dernière colonne) et $0 qui correspond à la ligne complète. Les champs peuvent être spécifiés par des expressions, comme $(NF-1) pour l'avant dernier champs.
  
 ====Le motif==== ====Le motif====
  
   * une expression régulière : "/regexp/" ; "expression ~ /regexp/" ou sa négation "expression !~ /regexp/"   * une expression régulière : "/regexp/" ; "expression ~ /regexp/" ou sa négation "expression !~ /regexp/"
-  * BEGIN ou END+Pour utiliser une variable bash comme regexp avec awk, on peut procéder ainsi : 
 +<code> 
 +awk '$1 ~ /^'$VAR'/ {print}' 
 +</code> 
 +  * BEGIN ou END (BEGIN permet de faire des actions avant le traitement du fichier ; END permet de les faire à la fin du traitement)
   * une comparaison (<, >, =>, !=, ...)   * une comparaison (<, >, =>, !=, ...)
-  * une combianison des 3 séparés d'un opérateur booléen (|| ou &&)+  * une combinaison des 3 séparés d'un opérateur booléen (|| ou &&)
  
 ====Les options==== ====Les options====
  
-  * ''-f <fichier>'' la commande s'applique à un fichier+  * ''-f <fichier>'' précise un fichier de script awk 
 +<code bash> 
 +vi test.awk 
 +BEGIN{FS=";"; OFS=" : "} 
 +$0 ~ "test" {print $0} 
 +:x 
 + 
 +awk -f test.awk fichier.txt 
 + ceci est un test 
 +</code>
   * ''-F "<séparateur>"'' spécifie le séparateur de champs (" " (espace) par défaut). NB : on peut spécifier plusieurs séparateurs en les séparant par "|" :   * ''-F "<séparateur>"'' spécifie le séparateur de champs (" " (espace) par défaut). NB : on peut spécifier plusieurs séparateurs en les séparant par "|" :
-<code>+<code bash>
 echo "toto;tata-titi" | awk -F":|-" '{print $1" "$2" "$3}' echo "toto;tata-titi" | awk -F":|-" '{print $1" "$2" "$3}'
  toto tata titi  toto tata titi
 +</code>
 +  * ''-v var="val"'' : permet d'affecter une valeur //val// à une variable //var// avant la partie BEGIN
 +<code bash>
 +HOST=toto ; echo titi | awk -v h=$HOST '{print "h="h}'
 + h=toto
 +</code>
 +
 +Autre façon de passer des variables dans un fichier de script :
 +<code bash>
 +vi test.awk
 +BEGIN{FS=";"; OFS=" : "}
 +$0 ~ rechch {print $0}
 +:x
 +
 +awk -f test.awk rechch=test fichier.txt
 + ceci est un test
 </code> </code>
  
 ====Les variables prédéfinies==== ====Les variables prédéfinies====
  
-''<variable>'' <desc> <valeur par défaut> +^ Variable ^ Description                                ^ Valeur par défaut ^ 
-  * ''ARGC'' Nombre d'arguments de la ligne de commande +ARGC     | nombre d'arguments de la ligne de commande || 
-  * ''ARGV'' tableau des arguments de la ligne de commnde +ARGV     | tableau des arguments de la ligne de commande  || 
-  * ''FILENAME'' nom du fichier sur lequel on applique les commandes +FILENAME nom du fichier sur lequel on applique les commandes || 
-  * ''FNR'' Nombre d'enregistrements du fichier +| ENVIRON  | tableau associatif des variables d'environnement || 
-  * ''FS'' separateur de champs en entrée +FNR      | nombre d'enregistrements parcourus du fichier courant || 
-  * ''NF'' nombre de champs de l'enregistrement courant +FS       | séparateur de champs (en entrée) | <tab>, <espace> ou <retour chariot> contigus | 
-  * ''NR'' nombre d'enregistrements deja lu +NF       | nombre de champs de l'enregistrement courant || 
-  * ''OFMT'' format de sortie des nombres +NR       | nombre d'enregistrements parcouru (tous fichiers confondus) || 
-  * ''OFS'' separateur de champs pour la sortie +OFMT     | format de sortie des nombres || 
-  * ''ORS'' separateur d'enregistrement pour la sortie +OFS      | séparateur de champs pour la sortie | <espace> | 
-  * ''RLENGTH'' longueur de la chaine trouvée +ORS      | séparateur d'enregistrement pour la sortie | <retour chariot> | 
-  * ''RS'' separateur d'enregistrement en entrée +| RLENGTH  longueur de la chaine trouvée || 
-  * ''RSTART'' debut de la chaine trouvée +RS       | séparateur d'enregistrement en entrée | <retour chariot> | 
-  * ''SUBSEP'' separateur de subscript+RSTART   | début de la chaine trouvée || 
 +SUBSEP   | séparateur de subscript ||
  
-====Les fonctions====+====Les fonctions texte====
  
-Les paramètres sont soit des chaines de caractère (s et t), soit des regexp (r) soit des entiers (i et n). +Les paramètres sont soit des chaines de caractères (s et t), soit des regexp (r) soit des entiers (i et n). 
-  * ''gsub(r,s,t)'' : sur la chaine t, remplace toutes les occurance de r par s   +  * ''gsub(r,s,t)'' : sur la chaine t, remplace toutes les occurrence de r par s 
-  * ''index(s,t)'' : retourne la position la plus à gauche de la chaine t dans la chaine s  +  * ''index(s,t)'' : retourne la position la plus à gauche de la chaine t dans la chaine s 
-  * ''length(s)'' : retourne la longueur de la chaine s   +  * ''length(s)'' : retourne la longueur de la chaine s 
-  * ''match(s,r)'' : retourne l'index ou s correspond à r et positionne RSTART et RLENTH   +  * ''match(s,r)'' : retourne l'index ou s correspond à r et positionne RSTART et RLENTH 
-  * ''split(s,a,fs)'' : split s dans le tableau a sur fs, retourne le nombre de champs   +  * ''split(s,a,fs)'' : split s dans le tableau a sur fs, retourne le nombre de champs 
-  * ''sprintf(fmt,liste expressions)'' : retourne la liste des expressions formatée suivant fmt   +  * ''sprintf(fmt,liste expressions)'' : retourne la liste des expressions formatée suivant fmt 
-  * ''sub(r,s,t)'' : comme gsub, mais remplace uniquement la première occurrence  +  * ''sub(r,s,t)'' : comme gsub, mais remplace uniquement la première occurrence
   * ''substr(s,i,n)'' : retourne la sous chaine de s commençant en i et de taille n   * ''substr(s,i,n)'' : retourne la sous chaine de s commençant en i et de taille n
 +  * ''tolower(s)'' : passer la chaîne en minuscules
 +  * ''toupper(s)'' : passer la chaîne en majuscules
 +  * ''count[s]'' : compte le nombre d’occurrence de s
 +
 +===Le cas printf===
 +
 +**printf** et ses dérivées sont des fonctions d'affichage de texte qui permettent de formater la sortie (pour un résultat bien léché comme on aime). Voici quelques cas d'utilisation commentés :
 +<code bash>
 +# afficher les logins et description des utilisateurs locaux qui utilisent le shell /bin/bash
 +# en alignant les logins à droite et sur 20 caractères
 +awk -F: '$7 ~ /\/bin\/bash/ {printf "%-20s %s\n", $1, $5}' /etc/passwd
 +root                 root
 +dude                 a dude
 +robert               le gros robert
 +
 +# puisque l'affichage est par colonne, on va afficher les noms pour être plus parlant
 +# on utilise l'instruction BEGIN qui, comme on l'a vu, ne s'exécute qu'une fois en début de script
 +awk -F: 'BEGIN {printf "%-20s %s\n", "login:","description:"} $7 ~ /\/bin\/bash/ {printf "%-20s %s\n", $1, $5}' /etc/passwd
 +login:               description:
 +root                 root
 +dude                 a dude
 +robert               le gros robert
 +
 +# on peut même définir un format d'affichage pour ne pas avoir a le retaper à chaque printf :
 +awk -F: 'BEGIN {format = "%-20s %s\n"; printf format, "login:","description:"; printf format, "---","---"} $7 ~ /\/bin\/bash/ {printf format, $1, $5}' /etc/passwd
 +login:               description:
 +---                  ---
 +root                 root
 +dude                 a dude
 +robert               le gros robert
 +
 +# la même commande, en plus lisible :
 +awk -F: 'BEGIN {format = "%-10s %s\n"
 + printf format, "login:","description:"
 + printf format, "---","---"}
 + $7 ~ /\/bin\/bash/ {printf format, $1, $5}' /etc/passwd
 +</code>
 +
 +====Les fonctions mathématiques====
 +
 +cos(x), exp(x), int(x), log(x), sin(x), sqrt(x), atan2(x,y), rand(x), srand(x)
  
 ====Exemples==== ====Exemples====
  
   * imprime chaque ligne du fichier /etc/passwd après avoir effacé le deuxième champs   * imprime chaque ligne du fichier /etc/passwd après avoir effacé le deuxième champs
-<code>+<code bash>
 awk -F ":" '{ $2 = "" ; print $0 }' /etc/passwd awk -F ":" '{ $2 = "" ; print $0 }' /etc/passwd
 </code> </code>
  
   * imprime le nombre total de lignes du fichiers   * imprime le nombre total de lignes du fichiers
-<code>+<code bash>
 awk 'END {print NR}' /etc/passwd awk 'END {print NR}' /etc/passwd
 </code> </code>
  
   * lire la 3ème ligne d'un fichier :   * lire la 3ème ligne d'un fichier :
-<code>+<code bash>
 awk '{if (NR==3) print}' <fichier> awk '{if (NR==3) print}' <fichier>
 </code> </code>
  
   * imprime le dernier champs de chaque ligne   * imprime le dernier champs de chaque ligne
-<code>+<code bash>
 awk '{print $NF}' /etc/passwd awk '{print $NF}' /etc/passwd
 </code> </code>
  
   * imprime le login et le temps de connexion.   * imprime le login et le temps de connexion.
-<code>+<code bash>
 who | awk '{print $1,$5}' who | awk '{print $1,$5}'
 </code> </code>
  
   * imprime les lignes de plus de 75 caractères. (''print'' équivaut à ''print $0'')   * imprime les lignes de plus de 75 caractères. (''print'' équivaut à ''print $0'')
-<code>+<code bash>
 awk 'length($0)>75 {print}' /etc/passwd awk 'length($0)>75 {print}' /etc/passwd
 </code> </code>
  
   * tests sur le fichier /etc/passwd :   * tests sur le fichier /etc/passwd :
-<code>+<code bash>
 awk 'BEGIN { print "Verification du fichier /etc/passwd pour ..."; awk 'BEGIN { print "Verification du fichier /etc/passwd pour ...";
             print "- les utilisateurs avec UID = 0 " ;             print "- les utilisateurs avec UID = 0 " ;
Line 100: Line 168:
  
   * supprimer le suffixe du domaine d'un nom de machine :   * supprimer le suffixe du domaine d'un nom de machine :
-<code>+<code bash>
 echo "toto.domaine.fr est un nom trop long !" | awk 'gsub(/\..*$/,"",$1) {print "machine="$1}' echo "toto.domaine.fr est un nom trop long !" | awk 'gsub(/\..*$/,"",$1) {print "machine="$1}'
 </code> </code>
  
 +  * afficher les blocs de texte du fichier FIC.txt compris entre les balises BEGIN et END :
 +<code bash>
 +awk '/BEGIN/,/END/' FILE.txt
 +</code> 
 +
 +  * supprimer (ne pas afficher) les doublons de lignes dans un fichier :
 +<code bash>
 +awk '!x[$0]++' test.tmp
 +</code>
 +
 +  * quitter la boucle awk après le premier match
 +<code bash>
 +echo -e "toto\ntoto\n" | awk '/toto/ {print; exit}'
 + toto
 +</code>
 +
 +  * émuler la fonction trim (efface les espaces avant et après une chaine) :
 +<code bash>
 +echo -e "toto   :titi\n   tata:tutu" | \
 + awk -F\: '{ sub(/^[ \t\r\n]+/, "", $1);sub(/[ \t\r\n]+$/, "", $1);print "\""$1"\""}'
 +</code>
 +
 +  * ne pas afficher les lignes en doublon
 +<code bash>
 +# count s'incrémente à chaque ligne déjà rencontrée ; on n'affiche donc la ligne qu'à sa première apparition
 +awk '!(count[$0]++)' fic.txt
 +</code>
 +
 +  * compter le nombre de caractère dans une ligne (k pour l'exemple)
 +<code bash>
 +echo $ligne | awk -F'k' '{print NF-1}'
 +</code>
 +
 +  * N'afficher que les lignes paires
 +<code bash>
 +awk 'NR%2==0' fic.txt
 +</code>
informatique/linux/awk.1272466231.txt.gz · Last modified: 2013/10/14 20:54 (external edit)