Outils de base de traitement du texte

Ce chapitre expose les notions et les outils de base pour traiter du texte sous Linux. On s’attachera aux notions de tubes et de redirections d’entrée et de sortie et leur interaction avec différents binaires POSIX comme cat, tac, head, tail, tee, wc, split, od, hexdump, cut, uniq, sort, paste, join, fmt, pr, tr et diff.

1. Redirections et tubes

https://wiki.bash-hackers.org/syntax/redirection

1.1. Redirections et tubes

Les processus UNIX ouvrent trois descripteurs de fichiers standards (correspondant aux flux standards) qui permettent de traiter les entrées et sorties. Ces descripteurs standards peuvent être redéfinis pour chaque processus. Dans la plupart des cas, le descripteur stdin (entrée standard) est le clavier, et les deux descripteurs de sortie, stdout (sortie standard) et stderr (l’erreur standard), sont l’écran.

Un processus et ses 3 descripteurs de fichiers STDIN (0), STDOUT (1) et STERR (2)

STDIN < ------ PROCESSUS ---- >
                   |     ---- >> STDOUT
                   |     ---- |
                   |
                   2>
                 STDERR

1.2. Redirection de l’entrée standard

programme < fichier

Dans ce cas, les données vont de droite à gauche. L’opérateur “<” ne peut être utilisé qu’avec stdin : on ne peut pas l’utiliser avec les flux de sortie.

Si le fichier contient les instructions l et q (une instruction par ligne), alors dans l’exemple suivant fdisk affichera la table des partitions de /dev/sda, puis affichera l’aide puis quittera :

cat > fdisk.txt
l
q
[CRTL-D]
su
fdisk /dev/?da < fdisk.txt
exit

Redirection de l’entrée standard :


PROCESSUS ---- < ---- FICHIER / PÉRIPHÉRIQUE
         ---- 0< ----

1.3. Etiquettes

Une étiquette permet de limiter la redirection. C’est utile par exemple pour donner des arguments à une commande sur plusieurs lignes. Un autre usage est la création de fichiers à partir d’un script. Dans l’exemple suivant, on envoie un émail sur plusieurs lignes avec la commande mail.

mail mon@adresse <<FIN
ceci
est
un
test
FIN

Exercice : Créer des fichiers avec un script bash.

Par exemple un script qui crée un fichier personnalisé :

#!/bin/bash
n=1
touch fichier-$n.txt
cat << EOF > fichier-$n.txt
Ceci est le fichier n°$n
Ligne 2
Ligne 3
Ligne 4
EOF
echo "fichier-$n créé"

1.4. Redirection de la sortie standard

Les données vont de gauche à droite.

programme > fichier

Par exemple, avec les droits de root :

fdisk -l /dev/?da > partitions.txt

Ceci lance fdisk et redirige la sortie vers le fichier partitions.txt. La sortie n’est pas visible a l’écran. Notez que le shell lit cette commande à partir de la droite : le fichier partitions.txt est d’abord créé s’il n’existait pas auparavant, écrasé dans le cas contraire car l’opérateur “>” est utilisé.

L’opérateur “>>” ajoute la sortie standard à un fichier sans l’écraser.

Redirection de la sortie standard :

          ---- > ----
PROCESSUS ---- >> ---- FICHIER / PÉRIPHÉRIQUE
          ---- 1> ----

1.5. Exemples de redirection de la sortie standard

  • > crée un nouveau fichier avec la sortie standard
  • >> ajoute la sortie au fichier

Par exemple :

date > date.txt
cat date.txt
dim fév 21 04:52:01 CET 2016
date >> date.txt
cat date.txt
dim fév 21 04:52:01 CET 2016
dim fév 21 04:53:09 CET 2016
date > date.txt
cat date.txt
dim fév 21 04:53:32 CET 2016

1.6. Redirection de la sortie erreur standard

programme 2> fichier_erreur

stdin, stdout et stderr sont représentés respectivement par 0, 1 et 2. Cela nous permet de choisir le flux d’erreur standard. Par exemple, vers une corbeille :

ls /fake / 2> /dev/null

Par exemple, vers un fichier :

ls /fake 2> err.txt

Redirection de l’erreur standard :

PROCESSUS ---- 2> ---- FICHIER / PÉRIPHÉRIQUE

1.7. Travailler avec les redirections

La commande suivante donne des erreurs et une sortie standard :

find /etc/ -name "*.crt"
/etc/ssl/certs/ca-certificates.crt
find: /etc/ssl/private: Permission denied
...

Isoler la sortie erreur :

find /etc/ -name "*.crt" > /dev/null
find: /etc/ssl/private: Permission denied

Isoler la sortie standard :

find /etc/ -name "*.crt" 2> /dev/null
/etc/ssl/certs/ca-certificates.crt

Diviser les sorties :

find /etc/ -name "*.crt" 2> /dev/null
/etc/ssl/certs/ca-certificates.crt
find /etc/ -name "*.crt" > crt.txt 2> crt.err
cat crt.txt
/etc/ssl/certs/ca-certificates.crt
cat crt.err
find: /etc/ssl/private: Permission denied

Rediriger une sortie vers l’autre, ici la sortie d’erreur sur la sortie standard :

find /etc/ -name "*.crt" 2>&1

Le symbôle &1 identifie la sortie standard demanière certaine. Sans le & la sortie d’erreur sera redirigée dans un fichier nommé 1.

Exemple final récapitulatif à méditer :

Avec le fichier fdisk.txt.

fdisk /dev/?da < fdisk.txt 2> /dev/null > resultat.txt

Le fichier fdisk.txt envoie des commandes en entrée à l’exécutable fdisk, le résultat sans les erreurs est écrit dans le fichier resultat.txt.

1.8. Tubes

programme1 | programme2

Les tubes (“pipe” en anglais) sont représentés par l’opérateur “|”. Les données vont de gauche à droite. La figure suivante indique comment la sortie standard du premier processus est redirigée vers l’entrée standard du second processus.

Redirection à partir d’un tube :

PROCESSUS1 (stdout) ---- | ---- (stdin) PROCESSUS2

Exemple : la sortie standard de la première commande devient l’entrée de la seconde commande.

ps aux | grep login

Note : L’utilitaire pgrep fournit le même résultat.

2. Outils de traitement du texte

2.1. cat : éditeur rudimentaire

La commande cat peut être utilisée comme un éditeur de texte rudimentaire.

cat > texte.txt
ligne 1
ligne 2
ligne 3
[Crtl+D]

Vous noterez l’utilisation de Ctrl+D. Cette commande est utilisée pour clore la saisie.

2.2. cat lecteur de texte

On utilise plus couramment cat pour envoyer du texte vers la sortie standard.

Les options les plus courantes sont :

  • -n numéroter chaque ligne de la sortie
  • -b numéroter uniquement les lignes non vides
  • -A afficher le retour charriot

Exemples :

cat texte.txt
ligne 1
ligne 2
ligne 3
cat -n /etc/resolv.conf

En fait, la commande cat concatène en sortie standard plusieurs fichiers mis en arguments de la commande.

2.3. tac lecteur inverse

tac fait la même chose que cat à l’exception qu’elle lit de la dernière ligne à la première.

tac texte.txt
ligne 3
ligne 2
ligne 1

2.4. head et tail

On utilise souvent les commandes head et tail pour analyser les fichiers de journaux. Par défaut, ces commandes affichent 10 lignes. En voici les utilisations les plus courantes :

Afficher les 20 premières lignes de /var/log/messages :

head -n 20 /var/log/messages
head -20 /var/log/messages

Afficher les 20 dernières lignes de /etc/aliases:

tail -20 /etc/aliases

tail a une option supplémentaire qui nous permet d’afficher la fin d’un texte en commençant par une ligne donnée.

Afficher le texte en partant de la ligne 25 de /var/log/messages

tail -n +25 /var/log/messages

tail peut afficher un fichier en continu avec l’option -f. C’est très pratique pour suivre les modifications d’un fichier en temps réel.

2.5. Commande tee

La commande tee permet à la fois de lire un flux et de le rediriger.

Par exemple, tee donne la sortie et l’écrit dans le fichier ls1.txt :

ls | tee ls1.txt

La sortie de la liste de fichiers dont on compte les lignes est redirigée vers la sortie standard et dans le fichier count.txt

ls -l *.txt | wc -l | tee count.txt

3. Manipulation de texte

  • Compter des lignes, des mots, des octets
  • Remplacer des tabulations par des espaces
  • Afficher les fichiers binaires
  • Découper les fichiers
  • Sélectionner les champs et les caractères avec cut
  • Trouver des doublons
  • Trier la sortie
  • Couper des fichiers
  • Jointure de texte
  • Mise en forme de la sortie avec fmt et pr
  • Convertir les caractères

3.1. Compter lignes, mots et octets avec la commande wc

La commande wc compte le nombre d’octets, de mots et de lignes dans les fichiers.

Les options suivantes vous permettent de sélectionner ce qui nous intéresse :

  • -l compte le nombre de lignes
  • -w compte le nombre de mots (words)
  • -c compte le nombre d’octets
  • -m compte le nombre de caractères
  • sans argument, wc compte ce qui est saisi dans stdin.

Par exemple :

wc -l /etc/passwd
cat /etc/passwd | wc -l

3.2. Remplacer les tabulations par des espaces

On utilise la commande expand pour remplacer les tabulations par des espaces.

unexpand est utilisé pour l’opération inverse.

3.3. Afficher les fichiers binaires

Il y a nombre d’outils pour cela. Les plus courants sont od (octal dump) et hexdump.

3.4. Découper les fichiers avec la commande split

La commande split peut découper un fichier en plusieurs fichiers plus petits à partir de critères comme la taille ou le nombre de lignes. Par exemple, nous pouvons découper /etc/passwd en fichiers de 5 lignes chacun :

split -l 5 /etc/passwd

Cette commande va créer des fichiers appelés xaa, xab, xac, xad, etc., chaque fichier contenant au plus 5 lignes. Tentez et vérifiez :

split -dl 5 /etc/passwd passwd

Il est possible de donner un préfixe plus significatif que “x”, comme “pass-5” :

split -l 5 /etc/passwd passwd-5

Cette commande crée des fichiers identiques à la commande précédente, mais ils sont désormais nommés passwd-5aa, passwd-5ab, passwd-5ac, passwd-5ad, …

3.5. Sélectionner les champs et les caractères avec cut

La commande cut peut extraire une plage de caractères ou de champs de chaque ligne d’un texte.

  • L’option -c est utilisée pour manipuler les caractères.
  • Syntaxe : cut –c {plage1,plage2}

Exemple :

cut -c5-10,15- /etc/passwd

Cette commande extrait les caractères 5 à 10 puis 15 jusqu’à la fin pour chaque ligne de /etc/passwd.

On peut spécifier le séparateur de champ (espace, virgule, etc.) d’un fichier ainsi que les champs à extraire. Ces options sont définies respectivement par les options -d (delimiter) et -f (field).

Syntaxe :

  • cut -d {séparateur} -f {champs}

Exemple :

cut -d: -f 1,7 --output-delimiter=" " /etc/passwd

Cette commande extrait les 1er et 7e champs de /etc/passwd séparés par un espace. Le délimiteur de sortie est le même que le délimiteur d’entrée d’origine (par défaut, la tabulation). L’option --output-delimiter vous permet de le changer.

3.6. Trouver des doublons avec la commande uniq

Éliminer les lignes successives en doublon : La commande uniq n’envoie à STDOUT qu’une version des lignes successives identiques. Par exemple :

uniq > /tmp/list1
ligne 1
ligne 2
ligne 2
ligne 3
ligne 3
ligne 3
ligne 1
^D
cat /tmp/UNIQUE
sort | uniq > /tmp/UNIQUE

3.7. Trier la sortie avec la commande sort

Par défaut, sort trie le texte par ordre alphabétique. Pour effectuer un tri numérique, utilisez l’option -n.

cat << EOF > /tmp/list2
ligne 1
ligne 2
ligne 2
ligne 1
ligne 3
ligne 2
ligne 3
ligne 1
EOF
sort /tmp/list2
sort /tmp/list2 | uniq > /tmp/list3

3.8. Jointure de texte avec paste

La commande la plus facile est paste qui “concatène” deux fichiers l’un à la suite de l’autre.

Syntaxe :

paste texte1 texte2

Exemples avec deux fichiers :

texte1 :

cat << EOF > texte1
01 Paris
02 Luxembourg
03 Berlin
04 Bruxelles
05 Londres
EOF

texte2 :

cat << EOF > texte2
01 France
02 Grand-Duché de Luxembourg
03 Allemagne
04 Belgique
05 Royaume-Uni
EOF
paste texte1 texte2
01 Paris	01 France
02 Luxembourg	02 Grand-Duché de Luxembourg
03 Berlin	03 Allemagne
04 Bruxelles	04 Belgique
05 Londres	05 Royaume-Uni
paste -s texte1 texte2
01 Paris	02 Luxembourg	03 Berlin	04 Bruxelles	05 Londres
01 France	02 Grand-Duché de Luxembourg	03 Allemagne	04 Belgique	05 Royaume-Uni
paste -s -d: texte1 texte2
01 Paris:02 Luxembourg:03 Berlin:04 Bruxelles:05 Londres
01 France:02 Grand-Duché de Luxembourg:03 Allemagne:04 Belgique:05 Royaume-Uni
paste -d: texte1 texte2
01 Paris:01 France
02 Luxembourg:02 Grand-Duché de Luxembourg
03 Berlin:03 Allemagne
04 Bruxelles:04 Belgique
05 Londres:05 Royaume-Uni

3.9. Jointure de texte avec join

Avec join vous pouvez en plus préciser quels champs vous souhaitez à condition que les fichiers disposent d’un début de ligne commun.

Syntaxe :

join -j1 {champ_no} -j2{champ_no} texte1 texte2

ou

join -1 {champ_no} -2{champ_no} texte1 texte2

Le texte n’est envoyé à la sortie que si les champs sélectionnés correspondent.

Les comparaisons se font ligne par ligne et le processus s’arrête dès qu’il n’y a pas de correspondance, même s’il y a d’autres correspondances à la fin du fichier.

Par exemple avec les fichiers précédents :

join texte1 texte2
01 Paris France
02 Luxembourg Grand-Duché de Luxembourg
03 Berlin Allemagne
04 Bruxelles Belgique
05 Londres Royaume-Uni

Exercice optionnel : Regroupez les fichiers séparés précédemment.

3.10. Mise en forme de la sortie avec fmt et pr

Vous pouvez modifier le nombre de caractères par ligne avec fmt. Par défaut fmt joint les lignes et génère des lignes de 75 caractères.

Options de fmt :

  • -w (width) nombre de caractères par ligne
  • -s découpe les lignes longues mais sans les remplir
  • -u sépare chaque mot par une espace et chaque phrase par deux espaces
  • On peut paginer les longs fichiers pour qu’ils correspondent à une taille donnée avec la commande pr. On peut contrôler la longueur des pages (66 lignes par défaut), la largeur (par défaut 72 caractères) ainsi que le nombre de colonnes.
  • Lorsqu’on produit un texte sur plusieurs colonnes, chaque colonne est tronquée uniformément en fonction de la largeur de page spécifiée. Cela veut dire que des caractères sont supprimés à moins d’avoir édité le texte de façon à éviter cela.

Par exemple :

curl -s https://lipsum.com/feed/json -o lipsum.txt
fmt < lipsum.txt

3.11. Convertir les caractères avec la commande tr

La commande tr convertit un ensemble de caractères en un autre.

Convertir les majuscules en minuscules :

tr 'A-B' 'a-b' < fichier.txt

Changer de délimiteur dans /etc/passwd

tr ':' ' ' < /etc/passwd
join texte1 texte2 | tr ' ' ':'
01:Paris:France
02:Luxembourg:Grand-Duché:de:Luxembourg
03:Berlin:Allemagne
04:Bruxelles:Belgique
05:Londres:Royaume-Uni

Remarque : tr a seulement deux arguments ! Le fichier n’est pas un argument.

3.12. Différentiel avec la commande diff

diff fichier1 fichier2