Telechargé par el_mamoun1

TP6 Unix Cmd

publicité
TP : commande awk
D'après le cours en ligne de Isabelle Vollant http://www.shellunix.com/awk.html
Nous reprenons dans ce TP une grande partie du cours de Isabelle Vollant en simplifiant quelques
informations.
Cette commande permet d'appliquer un certain nombre d'actions sur un fichier. La syntaxe est
inspirée du C.
Pour réaliser les exercices, vous récupérerez le répertoire de travail « fic_awk » composé de fichiers
de résultats à analyser.
Syntaxe
awk [-Fs] [-v variable] [-f fichier de commandes] 'program' fichier
-F Spécifie les séparateurs de champs
-v Définie une variable utilisée à l'intérieur du programme.
-f Les commandes sont lues à partir d'un fichier.
Principe de fonctionnement
Le programme awk est une suite d'actions de la forme : motif { action } , le motif permet de
déterminer sur quels enregistrements est appliquée l'action.
Un enregistrement est une chaîne de caractères séparée par un retour chariot, en général une
ligne.
Un champ est une chaîne de caractères séparée par un espace (ou par le caractère spécifié par
l'option -F), en général un mot.
On accède à chaque champ de l'enregistrement courant par la variable $1, $2, ... $NF. $0
correspond à l'enregistrement complet. La variable NF contient le nombre de champs de
l'enregistrement courant, la variable $NF correspond donc au dernier champ.
Donc la suite d'actions sera appliquée à tous les enregistrements qui vérifieront le motif. Lorsque
nous désirons faire une action une seule fois, alors on utilisera les variables BEGIN (quand on veut
que ce soit au début du programme) ou/et END (quand on veut que ce soit à la fin du programme).
Quelques variables prédéfinies
Variable
Signification
Valeur par défaut
ARGC
Nombre d'arguments de la ligne de commande
-
ARGV
Tableau des arguments de la ligne de commande
-
FNR
Nombre d'enregistrements du fichier
-
FILENAME Nom du fichier en entrée
-
FS
Séparateur de champs en entrée
'' ''
NF
Nombre de champs de l'enregistrement courant
-
NR
Nombre d'enregistrements déjà lus
-
RS
Séparateur d'enregistrements en entrée
''\n''
Quelques exemples très simples
Dans les exemples suivants il n'y a qu'un enchaînement de type motif { action } , et le seul motif
utilisé est dans le dernier exemple qui est le motif END. Donc dans les exemples toutes les actions
seront appliquées à tous les enregistrements du fichier en entrée
awk '{print $NF}' fichier : affiche le
dernier champ de chaque ligne du fichier (quand il n'y a
pas de motif particulier, l'action est faite pour tous les enregistrements)
who | awk '{print $1,$3}' : affiche le login et la date de connexion
awk 'END {print NR}' fichier : affiche le nombre total de lignes du fichier (affiche en fait à la
fin le nombre total d'enregistrements lus une fois, et non pour chaque enregistrement)
awk -F ":" '{ $2 = "" ; print $0 }' /etc/passwd : affiche chaque ligne du fichier
/etc/passwd après avoir effacé le deuxième champ (mis le deuxième champ à vide)
Exercice 1
Vous testerez dans cet exercice quelques lignes de commande utilisant la commande awk, en
utilisant comme fichier d'entrée le fichier ''timings_SPIR_CUDA_2500_194.txt'' se trouvant dans
l'archive à récupérer sur le site de l'enseignant, répertoire que vous recopierez sur votre compte.
1. Ecrire une ligne de commande qui fait la même chose que le 3e exemple (afficher le nombre
de total de lignes du fichier) mais avec d'autres variables.
2. Quelle différence alors entre NR et FNR ? Pour voir cette différence refaites une commande
qui affiche les 2 valeurs ligne après ligne, en donnant 2 fichiers à lire et non 1. Prenez un
autre fichier dans le répertoire AWK.
3. Ecrire une ligne de commande qui affiche pour chaque ligne (ou enregistrement) son
numéro, son nombre de champs, et enfin la valeur de son dernier champ.
Syntaxe du motif
Si le motif existe dans l'enregistrement, l'action sera appliquée à la ligne.
Le motif peut être :
•
•
•
•
•
une expression régulière simple ou composée comme ci-après :
• /exp reg/ où ''exp reg'' est une simple expression régulière et dès qu'une ligne
contient une telle expression on lui applique l'action qui suit
• $0 ~ /exp reg/ : la ligne est une expression régulière de la forme '' exp reg''
• expression ~ /exp reg/ : la ligne contient une ''expression'' qui est de la
forme '' exp reg''
• expression !~ /exp reg/ : la ligne contient une ''expression'' qui n'est pas de
la forme '' exp reg''
une expression BEGIN ou END
une expression de comparaison: <, <=, == , !=, >=, >
une combinaison des trois (à l'aide des opérateurs booléens || ou, && et, ! négation)
une caractérisation des lignes
motif1,motif2 : chaque ligne entre la première ligne correspondant au motif1 et la première
ligne correspondant au motif2
Exemples :
•
Exemple 0
awk 'length($0)>75 {print}' fichier : affiche les lignes de plus de 75 caractères (chaque
enregistrement teste si sa ligne contient plus de 75 caractères et si oui alors exécute l'action qui est
d'afficher la ligne ($0)). ''print'' équivaut à ''print $0''.
•
Exemple 1
awk 'BEGIN { print "Verification des UID et GID dans le fichier
/etc/passwd";
FS=":"}
$3 !~ /^[0­9][0­9]*$/ {print "UID erreur ligne "NR" :\n"$0 }
$4 !~ /^[0­9][0­9]*$/ {print "GID erreur ligne "NR" :\n"$0 }
END
{ print "Fin" }
' /etc/passwd
Résultat :
Verification des UID et GID dans le fichier /etc/passwd
UID erreur ligne 14 :
clown:*:aaa:b:utilisateur en erreur:/home/clown:/bin:sh
GID erreur ligne 14 :
clown:*:aaa:b:utilisateur en erreur:/home/clown:/bin/sh
Fin
•
Exemple 2
awk 'BEGIN { print "Verification du fichier /etc/passwd pour ...";
print "- les utilisateurs avec UID = 0 " ;
print "- les utilisateurs avec UID >= 60000" ;
FS=":"}
$3 == 0 { print "UID 0 ligne "NR" :\n"$0 }
$3 >= 60000 { print "UID >= 60000 ligne "NR" :\n"$0 }
END
{ print "Fin" }
' /etc/passwd
Résultat :
Verification du fichier /etc/passwd pour ...
- les utilisateurs avec UID = 0
- les utilisateurs avec UID >= 60000
UID 0 ligne 5 :
root:*:0:b:administrateur:/:/bin/sh
UID >= 60000 ligne 14 :
clown:*:61000:b:utilisateur en erreur:/home/clown:/bin/sh
Fin
•
Exemple 3
awk 'BEGIN { print "Verification du fichier /etc/group";
print "le groupe 20 s'appelle t-il bien users ? " ;
FS=":"}
$1 == "users" && $3 ==20 { print "groupe "$1" a le GID "$3" !" }
END
{ print "Fin" }
' /etc/group
Résultat :
Verification du fichier /etc/group
le groupe 20 s'appelle t-il bien users ?
groupe users a le GID 20 !
Fin
•
Exemple 4
awk 'NR == 5 , NR == 10 {print NR" : " $0 }' fichier : affiche de la ligne 5
à la ligne 10 du fichier en entrée, chaque ligne précédée par son numéro
Exercice 2
Vous testerez, comme dans l'exercice 1, quelques lignes de commande utilisant la commande awk,
en utilisant comme fichier d'entrée le fichier ''timings_SPIR_CUDA_2500_194.txt''
1. Ecrire une commande qui permet d'afficher la dernière ligne du fichier.
2. Ecrire une ligne de commande qui permet d'afficher uniquement les lignes de la forme :
4.16user 2.30system 0:06.49elapsed 99%CPU (0avgtext+0avgdata 0maxresident)k
et qui met le numéro des lignes devant. Puis vous enrichirez la ligne de commande afin de compter
le nombre de lignes de cette même forme.
Exercice 3
Dans le fichier annuaire vous chercherez les lignes :
• qui ont un champ qui devrait contenir un numéro et qui contient autre chose : vous
afficherez alors un message en indiquant le nom du propriétaire et le n° de la ligne ;
• qui ont un numéro de portable qui n'en est pas un (qui commence par autre chose que 06),
vous afficherez alors un message ainsi que le nom du propriétaire et le numéro erroné ;
Vous pourrez écrire une seule ligne de commande en séparant les lignes par des '' ;'', ou écrire les
lignes de votre commande awk dans un script que vous nommez par exemple ''essai_awk'' et ensuite
vous pourrez lancer votre commande en tapant la ligne de commande suivante dans le terminal :
awk -f essai_awk
Les actions
Les actions permettent de transformer ou de manipuler les données, elles contiennent 1 ou plusieurs
instructions. Les actions peuvent être de différents types : fonctions prédéfinies, fonctions de
contrôle, fonctions d'affectation, fonctions d'affichage.
Les structures de contrôle
Présentation
Parmi les structures de contrôle, on distingue les décisions (if, else), les boucles (while, for, dowhile, loop) et les sauts (next, exit, continue, break).
Les décisions (if, else)
La syntaxe est la suivante:
if (condition)
instruction1
else
instruction2
Si vous avez une suite d'instructions à exécuter, vous devez les regrouper entre deux accolades.
Exemple:
awk ' BEGIN{print "test de l absence de mot de passe";FS=":"}
NF==7
{ #pour toutes les lignes contenant 7 champs
if ($2=="") # si le deuxième champ est vide (correspond au mot de passe crypté))
{ print $1 " n'a pas de mot de passe"} # on affiche le nom de l'utilisateur
($1=login) qui n'a pas de mot de passe
else
{ print $1 " a un mot de passe"} # on affiche le nom de l'utilisateur possédant un
mot de passe
}
END{print"C'est fini") ' /etc/passwd
Les boucles (while, for, do-while)
while, for et do-while sont issus du langage de programmation C.
1. while
La syntaxe de while est la suivante :
while
(condition)
instruction
Exemple:
awk ' BEGIN{print"affichage de tous les champs de passwd";FS=":"}
{ i=1 # initialisation du compteur à 1 (on commence par le champ 1)
while(i<=NF) # tant qu'on n'est pas en fin de ligne
{ print $i # on affiche le champ
i++ # incrémentation du compteur pour passer d'un champ au suivant
}
}
END{print"C'est fini") ' /etc/passwd
Exercice 3bis :
Ecrire une commande qui permet d'afficher la dernière ligne du fichier d'une manière différente que
dans l'exercice 2.
Exercice 4 :
Dans un fichier vous rechercherez et afficherez, pour chaque ligne le premier champ dont la
longueur est égale à Max_Long. Si la ligne ne contient pas un tel champ alors affichez un message
d'erreur pour indiquer que cette ligne-ci (numéro de la ligne) n'a pas de champ de cette longueur.
La valeur de Max_Long sera modifiée en fonction des fichiers.
Exemples : vous prendrez 10 pour le fichier annuaire ; vous prendrez 8 pour timings... ; vous
prendrez histoire_sans_fin et vous chercherez le premier mot qui est de longueur 3.
Dans cet exercice vous pourrez écrire vos lignes de commande dans un fichier les appeler ensuite en
tapant la commande awk -f .…
Exemple :
dans votre fichier ''essai_awk'' vous mettez les lignes suivantes
BEGIN{print" affichage de tous les champs de passwd";FS=":"}
{
for (i=1;i<=NF;i++) # initialisation du compteur à 1, on incrémente le compteur jusqu'à ce qu'on
atteigne NF (fin de la ligne)
{ print $i } # on affiche le champ tant que la condition n'est pas satisfaite
}
END{print"C'est fini")
Puis vous appelez votre fichier awk de la manière suivante :
awk -f essai_awk /etc/passwd
Vous pouvez également mettre dans un fichier shell votre commande complète, et appelez ensuite
votre fichier comme un exécutable
Exemple :
dans votre fichier ''essai_awk.sh'' vous mettez les lignes suivantes
awk 'BEGIN{print" affichage de tous les champs de passwd";FS=":"}
{
for (i=1;i<=NF;i++) # initialisation du compteur à 1, on incrémente le compteur jusqu'à ce qu'on
atteigne NF (fin de la ligne)
{ print $i } # on affiche le champ tant que la condition n'est pas satisfaite
}
END{print"C'est fini")' $1
Puis vous appelez votre fichier awk de la manière suivante :
./essai_awk.sh /etc/passwd
2. for
La syntaxe de for est la suivante:
for (instruction de départ; condition; instruction d'incrémentation)
instruction
Exemple:
awk ' BEGIN{print" affichage de tous les champs de passwd";FS=":"}
{
for (i=1;i<=NF;i++) # initialisation du compteur à 1, on incrémente le compteur jusqu'à ce qu'on
atteigne NF (fin de la ligne)
{ print $i } # on affiche le champ tant que la condition n'est pas satisfaite
}
END{print"C'est fini") ' /etc/passwd
Avec for on peut travailler avec des tableaux.
Soit le tableau suivant: tab[1]="patate", tab[2]="courgette",tab[3]="poivron".
Pour afficher le contenu de chacun des éléments du tableau on écrira:
for (index in tab)
{
print "legume :" tab[index]
}
3. do-whileF
La syntaxe de do-while est la suivante:
do
{instructions}
while (condition)
La différence avec while, est qu'on est sûr que l'instruction est exécutée au moins une fois.
Sauts controlés (break, continue, next, exit)
1. break
Cette commande permet de sortir d'une boucle, la syntaxe est la suivante:
for (;;) #boucle infinie
{instructions
if (condition) break
}
Alors que break permet de sortir d'une boucle, continue force un nouveau passage dans une
boucle.
next permet d'interrompre le traitrement sur la ligne courante et de passer à la ligne suivante
(enregistrement suivant).
exit permet d'abandonner la commande awk, les instructions suivant END sont exécutées (s'il y en
a).
Exercice 5 :
Vous allez à partir du fichier ''Notes_SE.txt'', calculer la moyenne de chaque étudiant et l'afficher.
Dans ce fichier :
• une ligne correspond à toutes les notes d'un étudiant ;
• tous les étudiants n'ont pas le même nombre de notes (absent justifié) ;
• certains champs contiennent la mention ''ABI'', qui signifie que l'étudiant a une absence
injustifiée ce qui entraîne que la note correspondante est 0
Les tableaux
Présentation
Un tableau est une variable se composant d'un certains nombres d'autres variables (chaînes de
caractères, numériques,...), rangées en mémoire les unes à la suite des autres. Le tableau est dit
unidimensionnelle quand la variable élément de tableau n'est pas elle même un tableau. Dans le cas
de tableaux imbriqués on parle de tableaux unidimensionnels.
Les termes matrice, vecteur ou table sont équivalents à tableau.
Les tableaux unidimensionnels
Vous pouvez définir un tableau unidimensionnel avec la syntaxe suivante:tab[index]=variable,
l'index est un numérique (mais pas obligatoirement, voir les tableaux associatifs), la variable peut
être soit un numérique, soit une chaîne de caractère. Il n'est pas nécessaire de déclarer un tableau, la
valeur initiale des éléments est une chaîne vide ou zéro. Exemple de définition d'un tableau avec
une boucle for.
var=1
for (i=1;i<=NF;i++)
{ mon_tab[i]=var++}
On dispose de la fonction delete pour supprimer un tableau (delete tab). Pour supprimer un élément
de tableau on tapera delete tab[index].
Les tableaux associatifs
Un tableau associatif est un tableau unidimensionnel, à ceci près que les index sont des chaînes de
caractères.
Exemple:
age["olivier"]=27
age["veronique"]=25
age["benjamin"]=5
age["veronique"]=3
for (nom in age)
{ print nom " a " age[nom] "ans"
}
On a un tableau age avec une chaîne de caractères prénom comme index, on lui affecte comme
éléments de tableau un numérique (age de la personne mentionnée dans le prénom). Dans la
boucle for la variable nom est remplie successivement des chaînes de caractères de l'index
(olivier, veronique, ...).
Les valeurs de l'index ne sont pas toujours triées.
Exercice 6 :
Vous donnerez plusieurs fichiers en entrée de votre commande (ou programme) awk, fichier de
taille différente (ex : timings... et annuaire) et vous afficherez pour chaque fichier le nom et le
nombre de lignes et la 1ère et dernière ligne du fichier. Vous afficherez à la fin le nombre total de
lignes lues par votre programme à l'aide d'une variable prédéfinie, vous vérifierez que le nombre
donné correspond à la somme du total des lignes de chaque fichier.
Exercice 7 :
Vous écrirez un script qui permet, pour chaque répertoire TEST_* de calculer la moyenne du
nombre moyen de nœuds (''Avg Nodes'') pour toutes les données de tous les fichiers. De plus vous
chercherez le plus grand nombre de nombre moyen de nœuds pour chaque fichier et calculerez la
moyenne de ces maximums.
Téléchargement