
Cet article propose une découverte des processeurs de fichiers
sed
et awk
.
sed
est spécialise dans le traitement de données non organisées;
awk
dans le traitement des données formatées en lignes et colonnes.
Les fichiers utilisés dans cet article sont disponibles dans l’archive sedawk.tar.bz2.
L’utilisateur familié de ces commandes préférera sans doute la documentation de référence, plus approfondie.
Sommaire
La commande sed
Sed (Stream EDitor, éditeur de flux) effectue des transformations basiques d’un texte.
À ses débuts, l’éditeur ed
est doté d’une commande
travaillant sur son flux d’entrée standard. Elle permet d’afficher
toutes les lignes correspondant à une expression régulière.
Cette commande, dont la syntaxe s’écrit sous la forme g/re/p
(global/regular expression/print), donne naissance à l’utilitaire grep
.
La commande Sed est créée à partir de l’implémentation suivante de ed
.
Sed travaille uniquement sur le flux d’entrée standard tout en tirant ses instructions d’un fichier de scripts.
La version de sed
utilisée :
$ sed --version
GNU sed version 4.2.1
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE,
to the extent permitted by law.
GNU sed home page: <http://www.gnu.org/software/sed/>.
General help using GNU software: <http://www.gnu.org/gethelp/>.
E-mail bug reports to: <bug-gnu-utils@gnu.org>.
Be sure to include the word ``sed'' somewhere in the ``Subject:'' field.
La ligne de commande de sed
Le fonctionnement global de sed
:
- un texte est, lu à partir d’un fichier ou d’un tube, ligne après ligne;
- une ligne sur le flux d’entrée est lue;
- les diverses commandes traitent cette ligne;
- optionnellement, le résultat du traitement est envoyé sur la sortie standard.
sed [-n] [-e commande] [-f fichier de commandes] [fichier]
où les options ont la signification suivante :
-n
: écrit seulement les lignes spécifiées (par l’option/p
) sur la sortie standard.-e
: permet de specifier les commandes à appliquer sur le fichier. Cette option est utile lorque vous appliquez plusieurs commandes. Afin d’éviter que le shell n’interprète certains caractères, il est préférable d’insérer la commande entre deux caractères simple quote ’, ou entre deux caractères double quotes ".-f
: les commandes sont lues à partir d’un fichier.
L’affichage de lignes contenant un motif
L’équivalent de la commande cat
:
$ sed '' exemple.txt
La première ligne d'un exemple de texte.
C'est un texte avec des ereurs.
Beaucoups d'ereurs.
Une ligne ne contenant pas d'erreurs.
La dernière ligne de l'exemple de texte.
Pour afficher les lignes contenant un motif sur la sortie standard :
$ sed -n '/ereurs/p' exemple.txt
C'est un texte avec des ereurs.
Beaucoups d'ereurs.
Sans l’option -n
, sed
affiche chaque ligne lue, ainsi que chaque ligne contenant le motif recherché :
$ sed '/ereurs/p' exemple.txt
La première ligne d'un exemple de texte.
C'est un texte avec des ereurs.
C'est un texte avec des ereurs.
Beaucoups d'ereurs.
Beaucoups d'ereurs.
Une ligne ne contenant pas d'erreurs.
La dernière ligne de l'exemple de texte.
La commande suivante affiche les lignes d’un fichier qui contiennent un espace blanc :
$ sed -n '/[[:space:]]/p' exemple.txt
La première ligne d'un exemple de texte.
C'est un texte avec des ereurs.
Beaucoups d'ereurs.
Une ligne ne contenant pas d'erreurs.
La dernière ligne de l'exemple de texte.
Rechercher les lignes commençant par un premier motif et se terminant par un second motif :
$ sed -n '/^La.*texte.$/p' exemple.txt
La première ligne d'un exemple de texte.
La dernière ligne de l'exemple de texte.
On notera que le dernier point de l’expression régulière ^La.*texte.$
est nécessaire, puisqu’elle correspond à tout caractère, y compris le caractère fin de ligne.
La suppression
Supprimer les lignes contenant un motif :
$ sed '/ereurs/d' exemple.txt
La première ligne d'un exemple de texte.
Une ligne ne contenant pas d'erreurs.
La dernière ligne de l'exemple de texte.
Supprimer toutes les lignes vides d’un fichier :
$ sed /^$/d exemple.txt
Supprimer les lignes commençant par la chaîne L
:
$ sed /^L/d exemple.txt
C'est un texte avec des ereurs.
Beaucoups d'ereurs.
Une ligne ne contenant pas d'erreurs.
Supprimer les lignes numéro 2 et 4 :
$ sed '2d; 4d' exemple.txt
La première ligne d'un exemple de texte.
Beaucoups d'ereurs.
La dernière ligne de l'exemple de texte.
Supprimer les lignes numéro 2 à 3 :
$ sed '2,4d' exemple.txt
La première ligne d'un exemple de texte.
La dernière ligne de l'exemple de texte.
Supprimer les deux premières lignes :
$ sed '3,$d' exemple.txt
La première ligne d'un exemple de texte.
C'est un texte avec des ereurs.
Équivalent à :
$ head -n 2 exemple.txt
La première ligne d'un exemple de texte.
C'est un texte avec des ereurs.
La substitution
La commande de substitution s
permet de substituer le résultat d’une expression régulière à un texte donné.
La substitution d’une chaîne par la chaîne vide est une suppression. La substitution d’une chaîne vide par une chaîne est une insertion.
Sa syntaxe est :
sed [adresse]s/expression/remplacement/options
Quelques options :
0..9
: indique que la substitution ne doit être effectuée que pour la n-ième occurence du motif;g
: (global) effectue les modifications globalement sur toutes les occurences;p
: (print) affiche le contenu du tampon de travail (utilisé pour le déboguage);w file
: (write) écrit le résultat de la substitution dans le fichierfile
.
La substitution du premier motif d’une ligne
Substituer la première chaîne ereurs
par la chaîne erreurs
:
$ echo "ereurs ereurs" | sed 's/ereurs/erreurs/'
erreurs ereurs
Le même traitement sur chaque ligne du fichier exemple.txt
:
$ sed 's/ereurs/erreurs/' exemple.txt
La première ligne d'un exemple de texte.
C'est un texte avec des erreurs.
…
Supposons que l’on déplace le répertoire racine d’utilisateurs, de /krakatoa
vers /fujiyama
:
$ sed s!/krakatoa!/fujiyama!g /etc/passwd > /tmp/passwd.new
Attention car avec certains interpréteurs de commandes, comme bash
, le caractère !
est vu comme un historique. Dans ce cas là, il suffit d’en utiliser un autre :
$ sed s#/krakatoa#/fujiyama#g /etc/passwd > /tmp/passwd.new
Supprimer les 3 derniers chiffres d’une chaîne numérique :
$ echo "12345" | sed -e 's/[0-9]\{3\}$//'
12
Supprimer les 3 derniers chiffres d’une chaîne numérique et afficher le résultat à l’aide d’une référence arrière (back-reference) :
$ echo "12345" | sed -e "s/\([0-9]\)\{3\}$/ résultat = \1/"
12 résultat = 5
Supprimer le premier caractère d’une chaîne alphabétique :
$ echo "abcde" | sed -e "s/^[a-zA-Z]\{1\}//"
bcde
Supprimer le premier caractère d’une chaîne alphabétique et transformer le reste en majuscules :
$ echo "abcde" | sed -e "s/^[a-zA-Z]\{1\}//" | tr '[:lower:]' '[:upper:]'
BCDE
Supprimer les 2 premiers caractères d’une chaîne alphabétique et transformer certains caratères en majuscules :
$ echo "abcde" | sed -e "s/^[a-zA-Z]\{2\}//" | tr 'abcde' 'aBcDe'
cDe
La substitution globale
Substituer les chaînes erors
aux chaînes errors
:
$ echo "ereurs ereurs" | sed 's/ereurs/erreurs/g'
erreurs erreurs
Effectuer plusieurs substitutions :
$ sed -e 's/ereurs/erreurs/g' -e 's/dernière ligne/ligne finale/g' exemple.txt
La première ligne d'un exemple de texte.
C'est un texte avec des erreurs.
Beaucoups d'erreurs.
Une ligne ne contenant pas d'erreurs.
La ligne finale de l'exemple de texte.
N’effectuer la substitution uniquement pour les lignes contenant le mot rendez-vous
:
$ sed /rendez\-vous/s/soleil/lune/g fichier.in > fichier.out
Insérer une chaîne au début de chaque ligne :
$ sed 's/^/> /g' exemple.txt
> La première ligne d'un exemple de texte.
> C'est un texte avec des ereurs.
…
Insérer une chaîne à la fin de chaque ligne :
$ sed 's/$/EOL/g' exemple.txt
La première ligne d'un exemple de texte.EOL
C'est un texte avec des ereurs.EOL
Lister les fichiers du répertoire /usr/bin
dont la deuxième lettre est un a
:
$ ls /usr/bin | sed -n '/^.a/p' > filename.tmp.txt
Supprimer la troisième ligne du fichier temporaire :
$ head -n 3 filename.tmp.txt | tail -n 1
base64
$ sed '3,3d' filename.tmp.txt | grep base64
$ sed '3,3d' filename.tmp.txt > falename.tmp.txt
La commande awk
La commande awk
(Alfred, Weinberger et Kernighan)
est un processeur de fichier, spécialisé dans le traitement des données
formatées en lignes et colonnes. Sa syntaxe est inspirée de celle du langage C.
L’installation
Plusieurs implémentations utilisent la syntaxe du programme awk
:
nawk
: (New AWK) étend les fonctionnalités de la version initiale;mawk
: (Mike’s AWK) une version connue pour sa rapidité dans certains cas;gawk
: (Gnu AWK) la version GNU, avec une version dérivée pour travailler sur le réseau TCP/IP;jawk
: (Java AWK) une version fonctionnant sur une JVM.
L’implémentation awk
adoptée par la distribution Wheezy est gawk
.
Installer les paquets nécessaires :
$ sudo apt-get install gawk gawk-doc
Connaître l’implémentation de awk
utilisée :
$ type awk
awk est /usr/bin/awk
Lister les implémentations disponibles :
$ update-alternatives --list awk
/usr/bin/gawk
/usr/bin/original-awk
Obtenir plus d’informations sur les implémentations disponibles :
$ update-alternatives --display awk
awk - mode automatique
le lien pointe actuellement sur /usr/bin/gawk
/usr/bin/gawk - priorité 10
lien secondaire awk.1.gz : /usr/share/man/man1/gawk.1.gz
lien secondaire nawk : /usr/bin/gawk
lien secondaire nawk.1.gz : /usr/share/man/man1/gawk.1.gz
/usr/bin/original-awk - priorité 0
lien secondaire awk.1.gz : /usr/share/man/man1/original-awk.1.gz
La « meilleure » version actuelle est « /usr/bin/gawk ».
Changer d’implémentation par défaut :
$ update-alternatives --config awk
Il existe 2 choix pour l'alternative awk (qui fournit /usr/bin/awk).
Sélection Chemin Priorité État
------------------------------------------------------------
0 /usr/bin/gawk 10 mode automatique
1 /usr/bin/gawk 10 mode manuel
* 2 /usr/bin/original-awk 0 mode manuel
Appuyez sur <Entrée> pour conserver la valeur par défaut[*] ou choisissez le numéro sélectionné :0
Connaître la version de awk
:
$ awk --version
awk version 20110810
Connaître la version de gawk
:
$ awk -W version
GNU Awk 4.0.1
L’aide de awk
:
$ awk --help
Le manuel et l’information sur awk
:
$ man awk
$ info awk
Le guide de l’utilisateur The GNU Awk User's Guide
:
$ elinks file:///usr/share/doc/gawk-doc/gawk-html/index.html
Les exemples du paquet gawk-doc
:
$ ls /usr/share/doc/gawk/examples
data misc network prog
La ligne de commande
La syntaxe de awk
est la suivante :
awk [-F] [-v var=valeur] 'programme' fichier
ou
awk [-F] [-v var=valeur] -f fichier-programme fichier
Les arguments :
-F
: doit être suivi du séparateur de champ (-F:
pour un:
comme séparateur de champ);-v
: définit une variable qui sera utilisée par la suite dans le programme;-f
: suivi du nom du fichier programme deawk
.
La structure du programme
est :
'motif1 { action1 } motif2 { action2 } …'
quand il n’y a pas de motif, l’action s’applique à toutes les lignes du fichier.
Le fonctionnement global de awk
Le fichier est lu séquentiellement ligne après ligne.
Chaque ligne du fichier est comparée successivement aux différents motifs et l’action du premier motif renvoyant la valeur vraie est exécutée.
Une fois la ligne sélectionnée, elle est découpée en champs selon le séparateur d’entrée FS
, qui par défaut correspond au caractère espace ou au caractère tabulation.
L’utilisation de awk
en ligne de commande pour émuler la commande cat
:
$ echo coucou | awk '{ print }'
coucou
Placer les commandes dans un fichier :
$ cat > print-awk.cmd << EOF
{ print }
EOF
$ chmod 755 print-awk.cmd
$ echo coucou | awk -f print-awk.cmd
coucou
On utilise un Here Documents <<
de Bash pour créer puis écrire le contenu du fichier print-awk.cmd
.
Les scripts awk
utilisent le shebang #!/usr/bin/awk -f
:
$ cat > print.awk << EOF
#!/usr/bin/awk -f
{ print }
EOF
$ chmod 755 print.awk
$ echo coucou | ./print.awk
coucou
Utilisation de awk
dans un script Bash :
$ cat > print-awk.sh << EOF
awk '{ print }'
EOF
$ chmod 755 print-awk.sh
$ echo coucou | ./print-awk.sh
coucou
Les enregistrements, les champs et le séparateur
awk
scinde les données d’entrée en enregistrements et les enregistrements en champ.
Un enregistrement est une chaîne d’entrée délimité par un retour chariot. Un enregistrement est référencé par la variable $0
.
Un champ est une chaîne délimitée par un espace dans un
enregistrement. Dans un enregistrement les champs sont référencés par
les variables $1
, $2
, …, $NF
, où $NF
est le dernier champ.
La variable prédéfinie FS
(Field Separator) FIXME valeur par défault.
Afficher les lignes du fichier /etc/passwd
:
$ awk '{print $0}' /etc/passwd
La commande équivalente avec cat
:
$ cat /etc/passwd
Afficher la liste des utilisateurs systèmes :
$ awk -F: '{print $1}' /etc/passwd
La liste des utilisateurs système n’ayant pas de mot de passe :
$ awk -F: '{ if ($2 == "") print $1 ": pas de mot de passe !" }' < /etc/passwd
Chaque enregistrement du fichier /etc/passwd
représente un utilisateur système. Les champs d’un enregistrement sont séparés par un caractère deux-points :
.
$ cat > passwd.awk << 'EOF'
#!/usr/bin/awk -f
BEGIN { FS=":"}
{ print "Enregistrement :" }
{ print $0 }
{ print "Champs :" }
{ print "identifiant : " $1 }
{ print "mot de passe : " $2 }
{ print "UID : " $3 }
{ print "GID : " $4 }
{ print "commentaire : " $5 }
{ print "répertoire : " $6 }
{ print "shell : " $7 }
EOF
$ chmod 755 passwd.awk
$ head -1 /etc/passwd | ./passwd.awk
Enregistrement :
root:$6$ZgID92lJ$JyxrYo…:0:0:root:/root:/bin/bash
Champs :
identifiant : root
mot de passe : $6$ZgID92lJ$JyxrYoB5j…
UID : 0
GID : 0
commentaire : root
répertoire : /root
shell : /bin/bash
Transformer des lignes de la forme Username:Firstname:Lastname:Telephone number
sous la forme d’une entrée d’un annuaire LDAP :
dn: uid=Username, dc=example, dc=com
cn: Firstname Lastname
sn: Lastname
telephoneNumber: Telephone number
$ cat > data.txt << EOF
Alice:Merveille:Lastname1:0102030405
Bob:Sleigh:Lastname2:0506070809
Eve:Tentation:Lastname3:1011121314
EOF
$ cat > data2ldap.awk << 'EOF'
#!/usr/bin/awk -f
BEGIN { FS=":"; }
{
print "dn: uid="$1", dc=example, dc=com"
print "cn: " $2 " " $3
print "sn: " $3
print "telephoneNumber: " $4
}
EOF
$ chmod 755 data2ldap.awk
$ ./data2ldap.awk data.txt
dn: uid=Alice, dc=example, dc=com
cn: Merveille Lastname1
sn: Lastname1
telephoneNumber: 0102030405
…
Les blocs BEGIN
et END
Deux blocs spéciaux permettent d’ajouter des instructions à exécuter avant la lecture du premier enregistrement, le bloc BEGIN
et après la lecture du dernier enregistrement, le bloc END
.
Le bloc BEGIN
est utilisé pour :
- afficher un en-tête avant l’exécution du bloc principal;
- la déclaration de variables;
- l’initialisation de variables pour les opérations d’incrémentation et de décrémentation dans le bloc principal.
Le bloc END
est utilisé pour :
- afficher un résultat final après l’exécution du bloc principal.
Afficher un en-tête, les deux dernières lignes du fichier /etc/passwd
, suivi d’un pied de page sur la sortie courante :
$ cat > begin-end.awk << 'EOF'
#!/usr/bin/awk -f
BEGIN { print "*** begin ***" }
{ print $0 }
END { print "*** end ***" }
EOF
$ chmod 755 begin-end.awk
$ tail -2 /etc/passwd | ./begin-end.awk
*** begin ***
rtkit:x:123:129:RealtimeKit,,,:/proc:/bin/false
postgres:x:124:130:PostgreSQL administrator,,,:/var/lib/postgresql:/bin/bash
*** end ***
La liste des utilisateurs système :
$ awk 'BEGIN { FS = ":" } { print $1 }' /etc/passwd
Afficher les deux dernières lignes du fichier /etc/passwd
, équivalent à la commande tail -2
:
$ awk '{ y=x "\n" $0; x=$0 }; END { print y }' /etc/passwd
Afficher la dernière ligne du fichier /etc/passwd
, équivalent à la commande tail -1
:
$ awk '{ rec=$0 } END { print rec }' /etc/passwd
Afficher la suite des sommes cumulées des nombres de la troisième colonne du fichier numbers.txt
:
$ cat > numbers.txt << EOF
1 2 78
2 3 56
3 4 21
EOF
$ awk 'BEGIN { s=0 } { s=s+$3; print s }' numbers.txt
78
134
155
Afficher la somme des nombres de la première colonne du fichier numbers.txt
:
$ awk '{ s=s+$1 } END { print s }' numbers.txt
6
Quelques variables
La variable FIELDWIDTHS
FIELDWIDTHS
: liste des tailles de champs.
Formatter des données en colonnes :
$ cat > fieldwidths.txt << EOF
10:06pm up 21 days, 14:04, 23 users
User tty login idle JCPU PCPU what
hzuo ttyV0 8:58pm 9 5 vi p24.tex
hzang ttyV3 6:37pm 50 -csh
eklye ttyV5 9:53pm 7 1 em thes.tex
EOF
$ cat > fieldwidths.awk << 'EOF'
BEGIN { FIELDWIDTHS = "9 6 10 6 7 7 35" }
NR > 2 {
idle = $4
sub(/^ */, "", idle) # strip leading spaces
if (idle == "") { idle = 0 }
if (idle ~ /:/) {
split(idle, t, ":")
idle = t[1] * 60 + t[2]
}
if (idle ~ /days/) { idle *= 24 * 60 * 60 }
print $1, $2, idle
}
EOF
$ chmod 755 fieldwidths.awk
$ awk -f fieldwidths.awk fieldwidths.txt
hzuo ttyV0 9
hzang ttyV3 50
eklye ttyV5 7
Les variables ORS
et OFS
OFS
: (Output Field Separator) séparateur de champs pour la sortie, valeur par défaut " ";ORS
: (Output Record Separator) séparateur d’enregistrement pour la sortie, valeur par défaut\n
.
Trouver la ligne du fichier data.txt
contenant le premier champs de plus grande taille :
$ awk '$1 > max { max=$1; maxline=$0 }; END { print max, maxline }' data.txt
Afficher la liste des tailles maximuns des colonnes du fichier data.txt
:
$ cat > vars-ors-ofs-pre.awk << 'EOF'
#!/usr/bin/awk -f
BEGIN { FS=":" }
{
for (i=1; i<=NF; i++) {
l=length($i)
if (l>max[i]) { max[i]=l }
}
}
END {
fieldwidths = max[1]
for (i=2; i<=NF; i++) { fieldwidths = fieldwidths " " max[i] }
print fieldwidths
}
EOF
$ chmod 755 fieldwidths.awk
$ ./fieldwidths.awk data.txt
5 9 8 10
Pour transformer le fichier data.txt
:
$ awk -F: '{ printf "%-5s %9s %8s %10s\n", $1, $2, $3, $4 }' data.txt > data.out.txt
$ cat data.out.txt
Alice Merveille Lastname 0102030405
Bob Sleigh Lastname 0506070809
Eve Tentation Lastname 1011121314
$ cat > vars-ors-ofs.awk << 'EOF'
#!/usr/bin/awk -f
BEGIN {
FIELDWIDTHS="6 10 9 11"
OFS=" |"
n=split(FIELDWIDTHS, array, " ")
array[n+1]=length(OFS)*n # taille des n séparateurs des n+1 colonnes
array[n+2]=3 # taille de première colonne
for (i in array) { l+=array[i] }
for (i=0; i<l; i++) { ORS = ORS "-" }
ORS = ORS "\n"
print $ORS
}
{
print " "NR," "$1, $2, $3, $4
}
EOF
$ chmod 755 vars-ors-ofs.awk
$ ./vars-ors-ofs.awk data.out.txt
----------------------------------------------
1 | Alice | Merveille | Lastname | 0102030405
----------------------------------------------
2 | Bob | Sleigh | Lastname | 0506070809
----------------------------------------------
3 | Eve | Tentation | Lastname | 1011121314
----------------------------------------------
La variable FILENAME
FILENAME
: nom du fichier sur lequel on applique les commandes.
Utilisation basique de la variable FILENAME
:
$ echo 'texte 01' > filename01.txt
$ echo 'texte 02' > filename02.txt
$ cat > filename.awk << 'EOF'
#!/usr/bin/awk -f
BEGIN { f=""; }
{
if (f != FILENAME) {
print "Lecture du fichier", FILENAME;
f=FILENAME;
}
print;
}
EOF
$ chmod 755 filename.awk
$ ./filename.awk filename01.txt filename02.txt
Lecture du fichier filename01.txt
texte 01
Lecture du fichier filename02.txt
texte 02
Les variables NF
et NR
NF
: (Number of Fields) nombre de champs de l’enregistrement courant;$NF
: valeur du dernier champs.
NR
: (Number Records) nombre d’enregistrements déjà lu.
Sélectionner les premières et dernières colonnes de la sortie de la commande ls -l
:
$ ls -l | awk '{ print $1, $9 }'
total
-rwxr-xr-x awk-print.cmd
-rwxrwxrwx awk-print.sh
…
Une généralisation de la commande précédante. Le nombre de champs de la commande ls -l
est variable d’un système à l’autre; Berkeley a 8 champs et System V a 9 champs.
$ ls -l | awk '{ print $1, $NF }'
total 124
-rwxr-xr-x awk-print.cmd
-rwxrwxrwx awk-print.sh
…
Supprimer les lignes blanches du fichier /etc/passwd
:
$ awk NF /etc/passwd
Numéroter des lignes du fichier /etc/passwd
:
$ awk '{ print NR, $0 }' /etc/passwd
1 root:$6$ZgID92lJ$JyxrYoB5jg…:0:0:root:/root:/bin/bash
2 daemon:x:1:1:daemon:/usr/sbin:/bin/sh
…
Dénombrer les lignes du fichier /etc/passwd
:
$ awk 'END { print NR }' /etc/passwd
Afficher la première ligne du fichier /etc/passwd
, équivalent à la commande head -1
:
$ awk 'NR > 1 { exit }; 1' /etc/passwd
Afficher les 10 premières ligne du fichier /etc/passwd
, équivalent à la commande head -10
:
$ awk 'NR < 11' /etc/passwd
Afficher la 12ème ligne du fichier /etc/passwd
:
$ awk 'NR==12' /etc/passwd
Équivalent à :
$ head -12 /etc/passwd | tac | line
Afficher les lignes du fichier /etc/passwd
dont le numéro est compris entre 8 et 12 :
$ awk 'NR==8,NR==12' /etc/passwd
Équivalent à :
$ head -12 /etc/passwd | tail -5
Dénombrer les lignes, les mots et les caractères du fichier /etc/passwd
:
FIXME
Équivalent à :
$ wc /etc/passwd | awk '{ print $1, $2, $3 }'
52 80 2637
Les variables ARGV
et ARGC
ARGV
: tableau des arguments de la ligne de commande;ARGC
: nombres d’arguments de la ligne de commande.
$ awk 'BEGIN { for (i=0; i<ARGC; i++) print "argv[" i "] = " ARGV[i] }' data=2 abc
argv[0] = awk
argv[1] = data=2
argv[2] = abc
L’option -v var=value
définit la variable var
avec la valeur value
avant que l’exécution du programme commence. La valeur d’une telle variable est dispoble dans la règle BEGIN
.
L’option -v
ne peut définir qu’une seule variable, mais elle peut être utilisée plus d’une fois : awk -v foo=1 -v bar=2 …
Afficher les arguments de la commande awk
:
$ cat > args-show.awk << 'EOF'
BEGIN {
printf "A=%d, B=%d\n", A, B
for (i=0; i<ARGC; i++) {
printf "\tARGV[%d] = %s\n", i, ARGV[i]
}
}
END { printf "A=%d, B=%d\n", A, B }
EOF
$ chmod 755 args-show.awk
$ awk -v A=1 -f args-show.awk B=2 /dev/null
A=1, B=0
ARGV[0] = awk
ARGV[1] = B=2
ARGV[2] = /dev/null
A=1, B=2
Passer des arguments au programme :
$ cat > args.awk << 'EOF'
BEGIN {
# Valeurs par défaut
outfile = "x"
count = 1000
if (ARGC > 4) { usage() }
i = 1
if (ARGV[i] ~ /^-[[:digit:]]+$/) {
count = -ARGV[i]
ARGV[i] = ""
i++
printf "valeur de count: %d\n", count
}
# test argv in case reading from stdin instead of file
if (i in ARGV) { i++ } # passe le nom du fichier de données.
if (i in ARGV) {
outfile = ARGV[i]
ARGV[i] = ""
printf "fichier de sortie : %s\n", outfile
}
s1 = s2 = "a"
out = (outfile s1 s2)
printf "valeur de out : %s\n", out
}
function usage(e) {
e = "utilisation : awk -f args.awk -- [-num] [file] [outname]"
print e > "/dev/stderr"
exit 1
}
EOF
$ chmod 755 args.awk
$ awk -f args.awk -- -3 file outname
valeur de count : 3
fichier de sortie : outname
valeur de out : outnameaa
La variable PROCINFO
PROCINFO
: tableau d’informations à propos du programme awk
courant.
$ cat > procinfo.awk << 'EOF'
#!/usr/bin/awk -f
BEGIN {
print "prgpid: " PROCINFO["prgpid"]
print "pid: " PROCINFO["pid"]
print "ppid: " PROCINFO["ppid"]
print "uid: " PROCINFO["uid"]
print "gid: " PROCINFO["gid"]
print "egid: " PROCINFO["egid"]
print "euid: " PROCINFO["ugid"]
}
EOF
$ chmod 755 procinfo.awk
$ ./procinfo.awk
prgpid:
pid: 29229
ppid: 531
uid: 1000
gid: 1000
egid: 1000
euid:
Les expressions régulières
Afficher les lignes du fichier /etc/passwd
contenant le caractère 2
:
$ awk '/2/ {print $0}' /etc/passwd
root:$6$ZgID92lJ$JyxrYoB5…:0:0:root:/root:/bin/bash
bin:x:2:2:bin:/bin:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
…
La commande équivalente avec grep
:
$ grep '2' /etc/passwd
Afficher les lignes du fichier /etc/passwd
ne contenant pas le caractère 2
:
$ awk '!/2/ {print $0}' /etc/passwd
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
…
Afficher le répertoire racine de chaque partition et l’espace occupé :
$ df -h | awk '/dev/ { print $6, $5 }'
/dev 0%
/ 7%
/boot 6%
/home 74%
…
Afficher pour chaque ligne du fichier /etc/passwd
vérifiant l’expression régulière /2/
, la ligne précédante :
$ awk '/2/ { print (x=="" ? "match on line 1" : x) }; { x=$0 }' /etc/passwd
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
games:x:5:60:games:/usr/games:/bin/sh
…
Afficher pour chaque ligne du fichier /etc/passwd
vérifiant l’expression régulière /2/
, la ligne suivante :
$ awk '/2/ { getline; print }' /etc/passwd
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
…
Afficher les lignes du fichier /etc/passwd
contenues entre la ligne vérifiant l’expression régulière /root/
et la ligne vérifiant l’expression régulière /sys/
:
$ awk '/root/,/sys/' /etc/passwd
Afficher les lignes du fichier /etc/passwd
dont le premier champs contient le caractère d
:
$ awk '$1~/d/ {print $0}' /etc/passwd
root:$6$ZgID92lJ$JyxrYoB5jg/fg…:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
…
Afficher les fichiers de configuration du répertoire /etc
commençant par a
ou x
:
$ ls /etc | awk '/^(a|x).*.conf$/ { print $0 }'
adduser.conf
apg.conf
Exemple :
$ echo abc | awk '{ gsub(//, "X") ; print }'
XaXbXcX
Les tableaux
Les tableaux sont associatifs : une clé peut être associée à une valeur unique. 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.
Le tableau unidimensionnel
Définir un élément du tableau tab
:
tab[index]=variable
Pour supprimer l’élément d’index index
du tableau tab
:
delete tab[index]
Pour supprimer un tableau tab
:
delete tab
Exemple d’un tableau associatif :
$ cat > array-create.awk << 'EOF'
#!/usr/bin/awk -f
BEGIN {
tabname[1]="olive"
tabname[5]="vert"
print tabname[1] ", " tabname[5] " et " tabname[3] "."
delete tabname[5]
tabname[3]="night."
print tabname[1] ", " tabname[5] " et " tabname[3] "."
delete tabname
print tabname[1] ", " tabname[5] " et " tabname[3] "."
age["olivier"]=27
age["veronique"]=25
age["john"]=3
for (name in age) { print name ": " age[name] }
}
EOF
$ chmod 755 array-create.awk
$ ./array-create.awk
olive, vert et .
olive, et night..
, et .
veronique: 25
john: 3
olivier: 27
Exemple : transformer une chaîne dans un tableau.
La fonction split(s, a, sep)
transforme la chaîne s
en un tableau a
en utilisant le délimiteur sep
.
set time = 12:34:56
set hr = `echo $time | awk '{split($0,a,":"); print a[1]}'` # = 12
set sec = `echo $time | awk '{split($0,a,":"); print a[3]}'` # = 56
# = 12 34 56
set hms = `echo $time | awk '{split($0,a,":"); print a[1], a[2], a[3]}'`
set hms = `echo $time | awk '{split($0,a,":"); for (i=1; i<=3; i++) print a[i]}'`
set hms = `echo $time | awk 'BEGIN{FS=":"}{for (i=1; i<=NF; i++) print $i}'`
Le parcours de tableau
$ cat > array.txt << EOF
5 I am the Five man
2 Who are you? The new number two!
4 . . . And four on the floor
1 Who is number one?
3 I three you.
EOF
$ cat > array-scan.awk << 'EOF'
# Enregistre la valeur 1 pour chaque mot.
{
for (i=1; i<=NF; i++) { used[$i]=1 }
}
# Trouve le nombre de mots distincts de plus de 4 caractères.
END {
for (x in used) {
if (length(x) > 4) {
++num_long_words
print x
}
}
print num_long_words, " mots de plus de 4 caractères."
}
EOF
$ chmod 755 array-scan.awk
$ awk -f array-scan.awk array.txt
three
number
floor
3 mots de plus de 4 caractères.
Le tri de tableau
Exemple : ordre par défault.
$ awk 'BEGIN { a[4]=4; a[3]=3; for (i in a) print i, a[i] }'
4 4
3 3
Exemple : utiliser un ordre pré-définit.
$ awk 'BEGIN { PROCINFO["sorted_in"]="@ind_str_asc"; a[4]=4; a[3]=3; for (i in a) print i, a[i] }'
3 3
4 4
Exemple : créer un ordre.
$ cat > array-sort.awk << EOF
{
if ($1 > max) { max = $1 }
arr[$1] = $0
}
END {
for (x = 1; x <= max; x++) { print arr[x] }
}
EOF
$ chmod 755 arraySort.awk
$ awk -f array-sort.awk array.txt
1 Who is number one?
2 Who are you? The new number two!
3 I three you.
4 . . . And four on the floor
5 I am the Five man
Les tableaux multidimensionnels
On peut simuler un tableau à deux dimensions.
Le principe repose sur la création de deux indices (i, j)
qu’on va concaténer avec SUBSEP
(i:j)
.
SUBSEP=":"
i="A",j="B"
tab[i,j]="coucou"
L’élément coucou
est indexé par la chaîne A:B
.
Exemple : un tableau multidimensionnel.
$ cat > array-multidimensionnel.awk << 'EOF'
BEGIN {
Colors[1,1] = "Red"
Colors[1,2] = "Green"
Colors[1,3] = "Blue"
Colors[2,1] = "Yellow"
Colors[2,2] = "Cyan"
Colors[2,3] = "Purple"
}
END {
for (i = 1; i <= 2; i++) {
for (j = 1; j <= 3; j++) {
printf "Colors[%d,%d] = %s\n", i, j, Colors[i,j];
}
}
}
EOF
$ chmod 755 array-multidimensionnel.awk
$ awk -f array-multidimensionnel.awk /dev/null
Colors[1,1] = Red
Colors[1,2] = Green
Colors[1,3] = Blue
Colors[2,1] = Yellow
Colors[2,2] = Cyan
Colors[2,3] = Purple
L’utilisation de la variable SUBSEP
:
$ cat > array-subsep.awk << EOF
BEGIN {
x=SUBSEP
a="Red" x "Green" x "Blue"
b="Yellow" x "Cyan" x "Purple"
Colors[1][0] = ""
Colors[2][0] = ""
split(a, Colors[1], x)
split(b, Colors[2], x)
print Colors[2][3]
}
EOF
$ chmod 755 array-subsep.awk
$ awk -f array-subsep.awk
Purple
Afficher la matrice transposée d’une matrice :
$ cat > array-transpose.txt << EOF
1 2 3 4 5 6
2 3 4 5 6 1
3 4 5 6 1 2
4 5 6 1 2 3
EOF
$ cat > array-transpose.awk << 'EOF'
{
if (max_nf < NF) { max_nf = NF }
max_nr = NR
for (x = 1; x <= NF; x++) { vector[x, NR] = $x }
}
END {
for (x = 1; x <= max_nf; x++) {
for (y = max_nr; y >= 1; --y) { printf("%s ", vector[x, y]) }
printf("\n")
}
}
EOF
$ chmod 755 array-transpose.awk
$ awk -f array-transpose.awk array-transpose.txt
4 3 2 1
5 4 3 2
6 5 4 3
1 6 5 4
2 1 6 5
3 2 1 6
Annexe
Les structures de contrôles :
if (test) { actions } else { actions }
while (test) { actions }
do { actions } while (test)
for (expr1; expr2; expr3) { actions }
for (var in tableau) { actions }
next
: passe à la ligne suivante;continue
: passe à l’élément suivant dans une boucle, hors d’une boucle, passe au motif suivant;break
: sort d’une boucle.
Les fonctions numériques :
int(x)
: valeur entière dex
;sqrt(x)
: racine carrée dex
;exp(x)
: exponentielle dex
;log(x)
: logarithme naturel dex
;sin(x)
: sinus dex
;cos(x)
: cosinus dex
;atan2(y,x)
: arctangente dex/y
dans l’intervalle[-pi, pi]
;rand()
: nombre aléatoire compris entre 0 et 1;srand(x)
: réinitialiser le générateur de nombre aléatoire.
Note : les angles sont exprimés en radian.
Les fonctions sur les chaînes de caractères
Les paramètres des fonctions :
s
ett
representent des chaînes de caractères;r
est une expression régulière;i
etn
sont des nombres entiers.
Les fonctions :
getline()
: lit l’entrée suivante d’une ligne, retourne0
si fin de fichier (EOF
),1
sinon;length(s)
: retourne la longueur de la chaînes
;index(s,t)
: retourne l’index de la sous-chaînet
dans la chaines
,0
sit
n’est pas une sous-chaîne des
;match(s,r)
: retourne l’index ous
correspond àr
et positionneRSTART
etRLENTH
;sub(r,s,t)
: commegsub
, mais remplace uniquement la première occurence;substr(s,i,n)
: retourne la sous-chaîne des
à partir de la positioni
et de taillen
;gsub(r,s,t)
: substitue les occurences der
pars
dans la chaînet
;split(s,a,fs)
: scindes
dans le tableaua
surfs
, retourne le nombre de champs;print
: fonction d’affichage;printf
: fonction d’affichage formaté;sprintf(fmt,liste expressions)
: retourne la liste des expressions formatées suivantfmt
.
Les variables prédéfinies
Les sources
- Sed - An Introduction and Tutorial de Bruce Barnett, ;
- La commande awk de Isabelle Vollant, ;
- Handy one-line scripts for Awk de Eric Pement, .