Astuce shell : afficher certaines lignes d'un résultat
Mise à jour 28/09/2009 : refonte et enrichissement de l'article suite aux commentaires reçus, merci à tous !
Dans les scripts shell, j'ai parfois besoin d'afficher certaines lignes d'un résultat comprenant un nombre de lignes variable.
$ cat liste.txt **Ligne d'en-tête** toto tata ... titi tutu $
Nous allons étudier 2 solutions possibles :
- solution basique avec head et tail
- solution avancée avec sed
Solution basique : head et tail
Avec les commandes head et tail, on peut n'afficher que les n premières ou dernières lignes d'un résultat.
$ head -n 1 liste.txt #affiche la première ligne **Ligne d'en-tête** $ tail -n 2 liste.txt #affiche les 2 dernières lignes titi tutu $
On peut également utiliser head et tail pour afficher toutes les lignes sauf les n premières ou dernières.
$ head -n -1 liste.txt #tout sauf la ligne 1 toto tata ... titi tutu $ tail -n +3 liste.txt #tout à partir de la ligne 3 tata ... titi tutu
Solution avancée : sed
Alternativement on peut utiliser sed, plus complexe mais bien plus puissant. Nous allons nous intéresser aux commandes d (pour delete) et p (pour print) ainsi qu'à l'option -n (sed affiche chaque ligne par défaut, -n inverse ce comportement et sed n'affichera plus les lignes par défaut). Notons également le caractère $, qui désigne la dernière ligne dans les commandes d et p de sed.
$ sed -n '2p' liste.txt #affiche la ligne 2 tata $ sed -n '$p' liste.txt #affiche la dernière ligne tutu $ sed '3d' liste.txt #supprime la ligne 3 **Ligne d'en-tête** toto ... titi tutu
Sed permet également de sélectionner des plages de lignes. La syntaxe la plus simple est la suivante :
$ sed '2,3d' liste.txt #supprime les lignes 2 à 3 **Ligne d'en-tête** ... titi tutu $ sed -n '3,$p' liste.txt #affiche de la ligne 3 à la fin tata ... titi tutu
Mais sed permet des comportements plus complexes en sélectionnant les lignes non pas avec des numéros mais avec des expressions régulières. Très utile pour créer un petit système de templates par exemple.
Les expressions régulières sont encadrées par des barres obliques ("/").
$ sed -n '1,/titi/p' liste.txt #affiche les lignes entre 1 et /titi/ **Ligne d'en-tête** toto tata ... titi $ sed -n '/toto/,/titi/p' liste.txt #affiche les lignes entre /toto/ et /titi/ toto tata ... titi
Note : sed sélectionne toujours la première ligne correspondant à l'expression régulière en cas de résultat multiple. Dans l'exemple ci-dessous, la première ligne correspondante est "foobaz" :
$ cat test.txt foo foobar foobaz baz bar $ sed '/foo/,/baz/d' #supprime les lignes entre /foo/ et /baz/ baz bar
Cela fonctionne aussi pour les expressions plus complexes, par exemple :
$ sed '/f[o]\\{2\\}/,/^b[:alpha:]\\?[rz]/d' bar
Conclusion
Avec ces quelques commandes, il devient possible de filtrer finement les lignes d'un résultat que l'on souhaite récupérer.