5. Les commandes - notion de filtre Unix

5.1. Définition d'un filtre Unix

Nombre de commandes Unix permettent de traiter un flux de données textuelles leur parvenant sur leur entrée standard, et restituent le résultat de leur opération sur la sortie standard : elles sont alors nommées filtres. Leur but principal est donc d'apporter une traitement particulier dans la chaine des traitements que constitue un script.

5.2. Les principaux filtres Unix

Cette section se bornera à citer les commandes incontournables pour l'écriture de scripts shell, il faudra donc se référer au man de chacune d'entre elles pour obtenir de plus amples renseignement quant à leur fonctionnement. La majorité d'entre elles se trouve dans le paquet debian coreutils !

Tableau 5. Opérateurs de tests portant sur des nombres :

commandedescription synthétique
awkRecherche et traite des modèles (langage de programmation à part entière, développé infra.)
base64Encoder/décoder des données et les afficher sur la sortie standard.
commCompare ligne à ligne deux fichiers triés.
compress uncompress gzip gunzip bzip2 bunzip2Compressent et décompressent des données.
cpio tarArchivent des données.
csplitDécoupe un fichier en sections définies par des lignes de contexte.
cutAffiche des parties sélectionnées des lignes.
expand unexpandConvertit les tabulations en espaces et vice-versa.
fmtFormate simplement du texte.
foldCoupe chaque ligne de texte à une longueur donnée.
grep egrep fgrep rgrep Afficher les lignes correspondant à un motif donné (expressions rationnelles).
headAffiche le début des fichiers.
joinFusionne les lignes de deux fichiers ayant des champs communs.
nlNumérote les lignes d'un fichier.
odAffiche le contenu d'un fichier en octal ou sous d'autres formats.
pasteRegroupe les lignes de différents fichiers.
prMet en forme des fichiers de texte pour l'impression.
ptxGénére un index croisé du contenu de fichiers.
revRenverse l'ordre des caractères pour chaque ligne.
sedFiltre et transforme des textes (commande développé infra.)
shufGénère des permutations aléatoires.
sort tsortTrie les lignes de fichiers texte
splitDécoupe un fichier en différentes parties
sum cksum md5sum sha1sum sha224sum sha256sum sha384sum sha512sumCalculent de sommes de contrôle (CRC).
taccat inversé...
tailAffiche la dernière partie de fichiers.
trConvertit ou élimine des caractères.
uniqSignale ou élimine les lignes répétées.
wcAffiche le nombre de lignes, de mots et d'octets d'un fichier.
xargs Construit et exécute des lignes de commandes à partir de l'entrée standard.

5.3. Les principales commandes

Comme la précédente, cette section ne fera que citer les commandes utiles à l'écriture de scripts shell.

Tableau 6. Opérateurs de tests portant sur des nombres :

commandedescription synthétique
basenameÉliminer le chemin d'accès et le suffixe d'un nom de fichier.
chroot 
dateAffiche ou configure la date et l'heure du système.
ddConvertit et copie un fichier.
dfIndique l'espace occupé par les systèmes de fichiers.
dirnameNe conserve que la partie répertoire d'un nom de fichier.
duÉvaluer l'espace disque occupé par des fichiers.
echo Affiche une ligne de texte.
envExécute un programme dans un environnement modifié.
factorAffiche les facteurs premiers d'un nombre.
groupsAffiche les groupes auxquels appartient un utilisateur.
hostidAffiche le numéro d'identification de l'hôte actuel.
id whoamiAffiche les UID et GID effectifs et réels.
installCopie des fichiers et positionne leurs attributs.
lognameAfficherle nom de connexion de l'utilisateur
niceExécute un programme avec un niveau de priorité (politesse) modifié.
nohupExécute une commande en la rendant insensible aux déconnexions, avec une sortie hors terminal
pathchkVérifie la validité et la portabilité d'un nom de fichier
printenvAffiche l'ensemble ou une partie des variables d'environnement.
printfFormate et affiche des données.
readlinkAffiche la valeur d'un lien symbolique.
seqAffiche une séquence de nombres.
shredÉcrit par dessus un fichier pour en camoufler le contenu, et optionnellement l'effacer.
sleepEndort un processus pour une durée déterminée.
statAffiche l'état d'un fichier ou d'un système de fichiers.
sttyModifie et afficher la configuration de la ligne de terminal.
syncVide les tampons du système de fichiers.
teeLit depuis l'entrée standard et écrit sur la sortie standard et dans des fichiers.
testVérifie le type d'un fichier, et comparer des valeurs.
touchModifie l'horodatage d'un fichier ; le crée s'il n'existe pas.
ttyAffiche le nom de fichier du terminal associé à l'entrée standard.
unameAffiche des informations sur le système.
users whoAfficher le nom des utilisateurs actuellement connectés sur cette machine.
yesAffiche indéfiniment une chaîne de caractères jusqu'à ce que le processus soit tué.

5.4. sed et awk

Deux des commandes filtres précédemment énumérées méritent une attention particulière car, outre les services qu'elles peuvent rendre dans le cadre du scripting, ce sont également des langages de programmation à part entière, dont l'étude sortirait toutefois du cadre présent document. Un survol de leur possibilité est toutefois nécessaire.

5.4.1. sed - Stream EDitor

Sed signifie "Stream EDitor" autrement dit "éditeur de flux". De par son mode de fonctionnement, Sed peut être défini comme un éditeur non-interactif.

L'éditeur de flux Sed lit les lignes d'un ou plusieurs fichiers ou depuis l'entrée standard, et y applique des commandes lues elles aussi depuis l'entrée standard sous forme d'expressions (commandes d'édition) ou depuis un fichier texte (script), et écrit le résultat du traitement sur la sortie standard. Il est possible de résumer ainsi le mécanisme de fonctionnement de Sed :

lecture d'une ligne sur le flux d'entrée
traitement de la ligne en fonctions des diverses commandes lues
affichage (ou non) du résultat sur la sortie standard
passage à la ligne suivante
 

Sed ne se limite toutefois pas à la simple lecture lecture séquentielle du flux d'entrée, il est possible de spécifier les lignes sur lequelles les commandes doivent opérer : elles acceptent des numéros de lignes, des intervalles, ou encore des expressions rationnelles (notées RE ou regex). La syntaxe d'utilisation est la suivante :

sed [-options] [commande] [<fichier(s)>]
ou sa forme plus complète :
sed [-n [-e commande] [-f script] [-i[.extension]] [l [cesure]] rsu] [commande] [<fichier(s)>]
 

La portée des traitements, bien que facultative, peut être indiquée, c'est l'adressage d'une ou plusieurs lignes, qui se traduit par la syntaxe :

[adresse[,adresse]][!]commande[arguments]
 

Le traitement à opérer n'est pas forcément unique ; plusieurs commandes peuvent être enchainées si elles sont entourées par des accolades :

[adresse[,adresse]][!]{commande1; commande2; commande3 }[arguments]
 

Les commandes suivent donc un éventuel adressage, et les plus courantes sont :

# : Commentaire (pas d'adressage autorisé).
q : Quitter (adressage autorisé) .
d : Suppression de la ligne (adressage autorisé) .
p : Affichage (adressage autorisé).
n : Ligne suivante (adressage autorisé).
s/ch1/ch2/ : substitution (adressage autorisé).
y/ch1/ch2/ : Transposition (adressage autorisé).
a\texte\ : Ajout sur la ligne(une adresse autorisée).
i\texte\ : Insertion (une adresse autorisée).
c \texte : Echange le contenu de la ligne par le texte (adressage autorisé).
r fichier : Lecture (et insertion) du fichier (une adresse autorisée).
w fichier : Ecriture dans un fichier (une adresse autorisée).
= : Affiche le n° de ligne courante (une adresse autorisée).
l [largeur] : Affiche les caractères non imprimables et tronque éventuellement à N la ligne (adressage autorisé).
 

En outre, la commande de substitution peut se voir spécifier des drapeaux indiquant sa portée par rapport à ligne traitée :

g :susbtitution globale.
[0-9]* : N° d'occurence à traiter.
p : Affichage de la ligne(nécessite l'option -n).
w fic_sortie : Enregistrement dans le fichier spécifié.
e : Evaluation et exécution par le shell.
I : Insensibilité à la casse.
 

Exemples d'adressages et de commandes :

for i in $(seq 1 20); do echo "Ligne $i" >> fic.txt; done : résultat ???
 
sed -n 3p fic.txt : affiche la ligne 3 du fichier.
sed -n 1~2p fic.txt : affiche toutes les deux lignes à compter de la ligne 1 du fichier.
sed -n '3,6 p' fic.txt : affiche les lignes 3 à 6 du fichier.
sed -n '/Ligne [123789][0]*/p' fic.txt : affiche les lignes correspondant au motif (ER) fourni entre les délimiteurs '/'.
sed -n '/Ligne 3/,/Ligne 12/ p' fic.txt : affiche les lignes comprises enter deux correpondances.
sed -n '2,/Ligne 6/ p' fic.txt : affiche les lignes 2 jusqu'àt la correspondance.
sed -n '/Ligne 5/,+5 p' fic.txt : affiche les 5 lignes suivant la correspondance.
 
sed '10,19 d' fic.txt : Supprime les lignes 10 à 19.
sed '/1[0-9] d' fic.txt : Supprime les lignes 10 à 19.
sed '2,/Ligne [569]/ s/Ligne/Bonjour/' fic.txt : Substitue Ligne par Bonjour sur les lignes 2 à 5 et affiche les autres sans modification.
sed -n '2,/Ligne [569]/ s/Ligne/Bonjour/' fic.txt : Substitue Ligne par Bonjour sur les lignes 2 à 5 les affiche.
sed -e "s/\([0-9][0-9]*\)/--\1--/" fic.txt : Substitue le n° suivant Ligne par -- numéro - via l'extraction de sous-chaine ciblée.
sed -e "s/\(Ligne\).*\([0-9][0-9]*\)/--\2 \1--/" fic.txt : Affiche le -- n° Ligne -- via l'extraction de 2 sous-chaines ciblées.
sed -n '1~2 s/Ligne/Bonjour/ p; $a\LA FIN' fic.txt : Substitue Ligne par Bonjour une ligne sur 2 et ajoute 'LA FIN' en fin de fichier.

Exemples d'utilisation commune de sed (mono-lignes) :

- Supprimer les lignes vides : sed '/^\t*$/d' .
- Supprimer les commentaires : sed 's/#.*$//' .
- insérer une ligne vide avant la ligne repérée par le motif : sed '/ER/{x;p;x;}' .
- insérer une ligne vide après la ligne repérée par le motif : sed '/ER/G' .
- insérer une ligne vide avant et après la ligne repérée par le motif : sed '/RE/{x;p;x;G;}' .
- compter les lignes d'un fichier : sed -n '$=' .
- Eliminer les espaces blancs en début de ligne : sed 's/^[ \t]*//'.
- Eliminer les espaces blancs en fin de ligne : sed 's/[ \t]*$//'.
- Aligner du texte à droite (ici 79° colonne) : sed -e :a -e 's/^.\{1,78\}$/ &/;ta' .
- Centrer du texte à droite (ici sur 80 colonnes) : sed -e :a -e 's/^.\{1,77\}$/ &/;ta' -e 's/\( *\)\1/\1/' .
- Renverser l'ordre des caractères : sed '/\n/!G;s/\(.\)\(.*\n\)/&\2\1/;//D;s/.//' .
- Formater des nombres décimaux : sed -e :a -e 's/\(.*[0-9]\)\([0-9]\{3\}\)/\1.\2/;ta' .

Sed est autrement plus riche que les fonctions basiques qui ont été décrites dans cette section, et mérite sûrement une étude plus poussée, ne serait-ce que par la lectrure attentive d'un des nombreux tutoriels qui vent être trouvés sur internet.

5.4.2. awk

awk est un autre outil particulièrement adapté au traitement de données textuelles, son nom provient des initiales de ses 3 concepteurs : AHO, WEINBERGER et KERNIGHAN. Il s'agit en fait d'un véritable langage de script mais ses fonctionnalités de base en font également un outil incontournable pour l'écriture de scripts.

La syntaxe de base est la suivante :

awk [options] '{actions [; action]}' [fichier]
ou
awk [options] -f script [fichier]
 

Si le fichier à traiter est omis, awk utilise les données arrivant sur son entrée standard.

Lors du parcours d'un fichier, awk procède au découpage de chacune des lignes (enregistrement) pour en extraire des variables (champs) sur lesquels il sera possible ensuite travailler. Ce découpage est effectué en fonction des valeurs d'un certain nombre de variables internes à awk :

Tableau 7. Opérateurs de tests portant sur des nombres :

variablevaleur par défautrôle
RS\n (newline)Record Separator : caractère séparateur d'enregistrement (lignes).
FSCaractères blancs (espaces ou séparations)Field Separator : caractère séparateur de champs.
OFSespaceOutput Field Separator : caractère séparateur de champ utilisé pour l'affichage.
ORS\n (newline)Output Record Separator : caractère séparateur d'enregistrement utilisé pour l'affichage.
Pour chacun des enregistrements lus, awk génère donc un certain nombre de variables utilisables dans le corps du script :

Tableau 8. Opérateurs de tests portant sur des nombres :

variablevaleur
$0L'enregistrement en cours de traitement (la ligne).
NFNombre de champs de l'enregistrement courant.
$1, $2, ... $NFLes champs découpés dans l'enregistrement courant.
NRNuméro de l'enregistrement courant (1 pour la première ligne, etc...)
FNRIndice de l'enregistrement courant relatif au fichier en cours de traitement.
FILENAMENom du fichier en cours de traitement.
Partant de là, il est déjà possible d'utiliser les fonctionnalités de base de awk pour récupérer et afficher certaines valeurs :

ps -edfal | awk '{print $3, $15}'
ps -edfal | awk '{print "Commande", $15, "lancee par", $3, "- durée :", $14}'
ls -l | grep -v total | awk '{ print "La taille du fichier",$9,"est",$5," octets."}'
 

Dans le dernier exemple, il est fait appel à la commande grep pour supprimer une ligne indiquant le total, alors que awk sait parfaitement procéder à la sélection des enregistrement sur lesquels le traitement doit porter en spécifiant une expression rationnelle qui devra être en concordance (~) ou non (!~) avec l'enregistrement entier (si rien n'est spécicifé) ou un champ particulier :

ls -l | awk '!/total/ { print "La taille du fichier",$9,"est",$5," octets."}'
ls -al | awk '$9 ~ /[a-w]+/ { print "La taille du fichier",$9,"est",$5," octets."}'
ls -al | awk '! /total/ && $9 !~ /^\./ { print "La taille du fichier",$9,"est",$5," octets."}'
 

La sélection de l'enregistrement peut également être conditionnée au test d'une variable interne à awk :

ls -l | awk 'NR==2 { print "La taille du fichier",$9,"est",$5," octets."}'
ls -l | awk 'NR==2 || NR==4 { print "La taille du fichier",$9,"est",$5," octets."}'
ls -l | awk 'NR==2, NR==4 { printf("La taille du fichier %s est %s octets.\n",$9, $5)}'

Il est également possible de faire exécuter un traitement particulier avant et après le traitement du flux via l'utilisation des mots clés BEGIN et END :

ls -l | awk 'BEGIN {print "Les fichiers correspondants :"} \
NR==2 || NR==4 { print "La taille du fichier",$9,"est",$5," octets."} \
END {print "============= FIN ================="}'
 

En définitive, lorsque le traitement commence à se complexifier de la sorte, mieux vaut le coder dans un fichier de script à part qui sera appelé via l'option -f lors de l'invocation de awk :

ls -l | awk -f ls.awk avec le fichier ls.awk contenant :
 


# Section BEGIN  => Appelée avant le traitement du flux
BEGIN {
	print "Les fichiers correspondants :"
}
# Un section traitant le flux
NR==2 || NR==4 {
	printf("La taille du fichier %s est %d octets\n",$9,$5)
} 
# Section END invoquée après la lecture du flux de données
END {
	print "============= FIN ================="
}
				

Note

awk permet de définir plusieurs sections de traitement pour le flux, lesquelles seront (conditionnellement) invoquées séquentiellement.

Ce survol de awk s'arrêtera là, mais pas les possibilités de cet incontournable outil, avec lequel il est possible de définir des variables de travail, des structures de contrôle (tests, boucles), de rediriger les entrées-sorties, d'appeler des fonctions prédéfinies ou créer ses propres fonctions...