Quand utiliser awk et sed
Publi� le 3 mai 2010
PNG - 2 ko, http://upload.wikimedia.org/wikipedia/commons/thumb/3/38/Gnome-terminal.svg/60px-Gnome-terminal.svg.png

Awk est une commande UNIX très puissante qui remplace les commandes de gestion de texte d'un SHELL Linux ou UNIX. Il est particulièrement adapté pour le parsing et la transformation de fichiers texte. Awk demande cependant l'apprentissage d'un nouveau langage macro, même s'il est assez aisé de l'appréhender.

Sed permet de “parser” des textes avec des expressions régulières grâce à quelques fonctions proposées (suppression, modification, ajout). Il est moins puissant que Awk puisque Awk fournit un pseudo-langage de programmation.

Dans certains cas et pour des raisons de performance il convient d'utiliser Awk ou Sed en lieu et place des commandes SHELL pour atteindre le même résultat.

Dans les expérimentations suivantes, le principe est de lire un fichier et d'appliquer des commandes de parsing texte en mode pipe.

Le texte représente :
-  2,668,421 lignes
-  342,838,486 caractères

Le système utilisé est un Intel Core 2 Duo E7300 de 2,66 Ghz avec 1,93Go de RAM.

Bilan

-  Awk est jusqu'à 4 fois plus rapide que cut
-  sort 2x plus lent avec Awk
-  Awk est 20% plus rapide que uniq - si le fichier est déjà trié l'écart se réduit
-  grep 2x plus lent avec Awk ou Sed
-  grep+expression régulière 60% plus rapide avec Sed
-  tail 15x moins rapide avec Awk

Conclusion

Utiliser awk pour faire un cut, uniq et Sed pour rechercher une expression régulière.

cut


$ time cat fichier | cut -f5 -d' ' | wc -l
2688421

real    0m34.375s
user    0m40.153s
sys     0m0.514s

cut avec Awk


$ time cat fichier | awk '{print $5}' | wc -l

2688421

real    0m8.609s
user    0m13.372s
sys     0m0.482s

sort


$ time cat fichier | sort | wc -l
2688421

real    0m18.297s
user    0m16.887s
sys     0m1.340s

sort avec Awk


$ time cat fichier | awk '{t[cpt]=$0;cpt++;} END {asort(t);for (i=0;i<cpt;i++) print t[i]}' | wc -l
2688421

real    0m28.672s
user    0m33.184s
sys     0m1.030s

uniq


# il faut faire un sort avant uniq
$ time cat fichier | cut -f5 -d' ' | sort | uniq | wc -l
267336

real    0m41.500s
user    0m50.589s
sys     0m0.590s

uniq avec Awk


$ time cat fichier | cut -f5 -d' ' | awk '!($0 in a) {a[$0];print}' | wc -l
267336

real    0m33.218s
user    0m40.965s
sys     0m0.450s

grep


$ time cat fichier | grep "/RefRouteur/" | wc -l
11775

real    0m9.953s
user    0m9.012s
sys     0m0.280s

grep avec Awk


$ time cat fichier | awk '/RefRouteur/ {print}' | wc -l
11775

real    0m14.844s
user    0m20.841s
sys     0m0.421s

grep avec Sed


$ time cat fichier | sed -n '/RefRouteur/p' | wc -l
11775

real    0m14.437s
user    0m20.778s
sys     0m0.388s

grep avec expression régulière


$ time cat fichier | egrep " [0-9]{6} " | wc -l
47045

real    0m40.735s
user    0m48.247s
sys     0m0.513s

grep avec expression régulière avec Awk


# la regexp a du être réécrite pour que awk la gère
$ time cat fichier | awk '/ [0-9][0-9][0-9][0-9][0-9][0-9] /' | wc -l
47045

real    0m40.125s
user    0m48.199s
sys     0m0.357s

grep avec expression régulière avec Sed


$ time cat fichier | sed -n -r "/ [0-9]{6} /p" | wc -l
47045

real    0m23.219s
user    0m30.716s
sys     0m0.436s

tail


$ time tail etude.log | wc -l
10

real    0m0.032s
user    0m0.076s
sys     0m0.015s

tail avec Awk


$ time awk 'NR > 2688411' etude.log | wc -l
10

real    0m1.234s
user    0m1.154s
sys     0m0.140s

D'autres commandes suivront ...