Filtrage de texte : sed, awk, etc.

Anne texte sed awk cut linux csv

Il y a plein d’outils disponibles pour filtrer du texte. Voilà des exemples que j’utilise souvent.

Filtrage des champs d’un fichier de type csv

On parle ici de fichiers formatés en colonnes, avec un séparateur simple (ie. le séparateur n’apparaît en aucun cas dans les colonnes). Je peux me permettre cette restriction, car c’est souvent moi qui les génère, je sais donc à quoi m’attendre.

Choix des colonnes

Pour simplement sélectionner les colonnes à voir, le plus simple est d’utiliser cut :

  • pour mentionner le séparateur, il faut utiliser l’option --delimiter=, ou -d,

  • pour sélectionner les champs, c’est l’option -field ou -f suivie des champs à sélectionner numérotés à partir de 1. Par exemple, pour afficher les champs jusqu’au 3$^e$, 6 à 8, et de 12 à la fin :

      $ cut --field=-3,6-8,12-
    
  • pour voir les champs qui ne sont pas dans la sélection précédente, il y a l’option --complement. Par exemple, pour supprimer la 3e colonne :

      $ cut --field=3 --complement
    

Reformatage

Si, en plus de sélectionner les colonnes, on veut par exemple en modifier l’ordre, ou encore modifier le formatage, il vaut mieux utiliser awk :

  • pour mentionner le séparateur, il faut utiliser l’option -F, (ou la variable FS dans la règle BEGIN)

  • pour transformer l’affichage, on utilise printf. Par exemple :

      awk -F, '{printf "%s --- %s : %s\n", $2, $4, ($6~/ok/ ? "OK" : "KO") }'
    

Tri

Pour trier suivant une colonne :

  • pour mentionner le séparateur, il faut utiliser l’option -t, (ou --field-separator=,)

  • pour choisir la colonne, c’est -k 2 (ou --key=2). Il faut noter qu’avec cette option, on peut aussi choisir le type de tri. Les plus courants sont:

    • -n (ou --numeric-sort)

    • -d (ou --dictionary-order)

      On peut aussi préciser:

    • -b (ou --ignore-leading-blanks)

    • -f (ou --ignore-case)

Par exemple :

$ sort -t, -k 12n,1f

(voir le man pour plus de détails).

sed

Pour ne garder que les lignes transformées

Pour ne garder que les lignes sur lesquelles on fait une transformation, on peut bien sûr utiliser grep:

$ xwininfo -root | grep "-geometry" | sed -e '^.* \([0-9]*\)x\([0-9]*\).*$/ ; w=\1 ; h=\2/'

Mais c’est quand même un peu dommage, alors qu’on peut faire la même chose avec juste sed:

$ xwininfo -root | sed -e '/^ *-geometry/!d ; s/^.* \([0-9]*\)x\([0-9]*\).*$/ ; w=\1 ; h=\2/'

Encore mieux lorsqu’on ne souhaite pas spécifier explicitement les lignes à garder, on peut simplement ne garder que celle qui subisse une transformation:

xwininfo -root \
  | sed -e 's/.*Width: \([0-9]*\)/w=\1/' \
              -e 's/.*Height: \([0-9]*\)/h=\1/' \
              -e 't' -e 'd' )

Le t signifie que si l’une des substitutions a été effectuée sur la ligne, on se branche à un label. Ici, on n’a pas spécifié le label, et on va donc à la fin du script. Sinon (la ligne ne correspond à aucun des filtres), on fait d, c’est à dire que l’on détruit la ligne.

Pour effacer le début d’un fichier jusqu'à une RE exclue

La commande suivante ne fait pas ce qu’on veut, car elle ne garde pas la ligne contenant toto :

$ sed -e "1,/toto/d" fichier.txt

Si on souhaite la garder, il faut faire:

$ sed -e "1,/toto/{/toto/b ; d}" fichier.txt

C’est semblable à l’autre, sauf que sur la ligne contenant toto, on se branche (b) à la fin de la commande (car on n’a pas précisé de label de branchement), c’est-à-dire qu’on ne détruit pas cette ligne (d).

Pour ne garder que les lignes entre deux RE

Effacer ce qui n’est pas entre les deux RE :

$ sed -e "/toto/,/titi/!d"

ou encore, ne rien afficher (option -n) sauf ce qui est entre les deux RE :

$ sed -n -e "/toto/,/titi/p"

Si on ne veux pas garder les lignes avec les RE :

$ sed -n -e "/toto/,/titi/{//!p}"

En effet, il faut savoir que // est équivalent aux dernières RE utilisées.

Si on ne veux garder que l’une des bornes (par exemple, on garde la ligne avec toto mais on supprime celle avec titi) :

$ sed -n -e "/toto/,/titi/{/titi/!p}"

Pour joindre toutes les lignes

On peut utiliser sed (avec N pour joindre deux lignes, et une boucle), mais il y a plus simple :

$ tr "\n" ", "

Pour mettre en majuscule

  • la première lettre : echo salut | sed 's/^./\u&/'

    donne : Salut

  • certaines lettres : echo "salut les lulus" | sed 's/[sl]/\u&/g'

    donne : SaLut LeS LuLuS

  • toute une expression : echo "salut les lulus" | sed 's/a[^ ]*/\U&/'

    donne : sALUT les lulus

Documentation

Des liens utiles au sujet de sed:

Voir aussi :