Séance 3 : Flux de données

Flux standards

Que fait le programme suivant ?

#include <readline/readline.h>

int main(int argc, char* argv[]) {
    char* nom = readline("Quel est votre nom ? ");
    printf("Bonjour %s !\n", nom);
}

Note

Réponse typique : il lit une chaîne depuis le clavier, puis affiche une chaîne à l'écran. Mais c'est en fait un cas pariculier de ce qu'il fait.

Sous Linux, la plupart des programmes démarrent avec 3 flux de données préalablement ouverts :

  • l'entrée standard, destinée à alimenter le programme en données,

  • la sortie standard, destinée à recevoir les résultats du programme,

  • l'erreur standard, destinée à recevoir les messages d'erreur générés par le programme.

Note

On emploie parfois le mot « fichier » plutôt que flux, bien qu'il prête à confusion.

https://upload.wikimedia.org/wikipedia/commons/7/70/Stdstreams-notitle.svg

Source: Wikipedia

Les processus lancés par le shell héritent de ses flux standard, et donc correspondent par défaut au clavier et a l'affichage du terminal.

Mais il est possible de changer cela.

Redirection

Une ligne de commande peut comporter un ou plusieurs des éléments suivants :

  • < suivi d'un nom de fichier (chemin)

  • > suivi d'un nom de fichier (chemin)

  • 2> suivi d'un nom de fichier (chemin)

Ces éléments redirigent (ou « rebranchent ») l'un des flux standards (l'entrée, la sortie et l'erreur standard, respectivement) sur le fichier indiqué.

Indication

Les redirections sont interprétéss par les shell avant d'exécuter le programme, et ne sont donc pas vues par le programme.

Exemple :

ls -l >mes_fichiers.txt

/dev/null

/dev/null est un fichier virtuel présent sur tous les systèmes UNIX.

Il agit comme un « trou noir », tout ce qui est écrit dans ce fichiers est simplement supprimé.

Exemple :

# n'affiche que les messages d'erreurs
# (répertoires non autorisés pour l'utilisateur)

ls /var/*/* >/dev/null

Redirection par ajout

Les redirections classiques > et 2> vident le fichier destination avant d'écrire dedans.

Si on souhaite conserver le contenu précédent du fichier, on peut utiliser à la place >> ou 2>>, respectivement.

Exemple :

ls -l Documents >>mes_fichiers.txt

Outils de manipulation de texte

Philosophie UNIX

  • chaque outil fait une seule chose, mais la fait bien

  • le SE offre des mécanismes pour combiner les outils

wc [options] — word count

Compte les mots (ou d'autres choses) sur son entrée standard.

En l'absence d'options, affiche le nombre de lignes, de mots et d'octets.

-c, --bytes

Affiche le nombre d'octets.

-w, --words

Affiche le nombre de mots.

-l, --lines

Affiche le nombre de lignes.

-L, --max-line-length

Affiche la longueur de la ligne la plus longue.

sort [OPTIONS]

Trie les lignes lues sur l'entrée standard, et les affiche dans l'ordre sur la sortie standard.

-r, --reverse

Inverse l'ordre du tri.

-n, --numeric-sort

Interprète les valeurs comme des nombres si possible.

Note

Dans l'ordre alphabétique (utilisé par défaut), 10 arrive avant 2 par exemple.

-k, --key=NUMÉRO

Le champs sur lequel trier (les champs sont délimitées par tous les types d'espaces).

Note

En fait l'option -k est beaucoup plus flexible que cela.

-t, --field-separator=CARACTÈRE

Utilise CARACTÈRE comme délimiteur de champs pour -k, au lieu des espaces.

cut [OPTIONS]

Reproduit sur sa sortie standard une sous-partie de chaque ligne lue sur son entrée standard.

-f, --fields=LIST

Ne conserve que les champs spécifiés par LIST, qui est une liste séparée par des virgules de numéros (le premier champs est a le numéro 1) ou de plages de numéros.

Les champs sont délimités par des tabulations.

-d, --delimiter=CARACTÈRE

Utilise CARACTÈRE comme délimiteur de champs pour -f, au lieu des tabulation.

-c, --characters=LIST

Ne conserve que les caractères spécifiés par LIST, avec la même syntaxe que pour -f.

Exemples d'utilisation de cut

# ne garde que les colonnes 1 et 3
cut -d, -f1,3   <data.csv  >columns.csv

# affiche les noms d'utilisateurs inscrits
cut -d: -f1   </etc/passwd

# tronque à 10 caractères chaque ligne de src
cut -c1-10   <src  >dest

egrep [OPTIONS] <regex>

N'affiche sur la sortie standard que les lignes (lues sur l'entrée standard) contenant l'expression régulière <regex>.

-i, --ignore-case

Ignore les différences de casse (différence majuscule/minuscule) entre le texte lu et l'expression régulière.

-v, --invert-match

Au lieu d'afficher les lignes qui contiennent <regex>, affiche celles qui ne la contiennent pas.

tr <set1> <set2> | tr -d <set1> — translate

Reproduit sur sa sortie standard le texte lu sur l'entrée standard, en modifiant (première variante) ou supprimant (deuxième variante) certains caractères.

<set1>

Une liste de caractères, énumérés en extension, ou sous forme de plages de caractères séparés par un tiret -.

Exemple : 02468, a-zàâéèêîôû, a-zA-Z

-c, --complement

Transforme les caractères qui n'appartiennent pas à <set1>.

<set2>

Une liste de caractères, suivant les mêmes règles que <set1>.

Chaque caractère de <set1> sera remplacé par le caractère correspondant de <set2>. Si <set2> est plus court que <set1>, le dernier caractère est implicitement répété autant de fois que nécessaire.

-d, --delete

Supprime les éléments de <set1>.

Exemples d'utilisation de tr

# remplace toutes les majuscules par des minuscules
tr A-Z a-z   <src  >dest

# remplace tous les chiffres par X
tr 0-9 X   <src  >dest

# remplace tout ce qui n'est pas une lettre par une espace
tr -c A-Za-z " "   <src  >dest

# supprime les espaces, tabulations, retours à la ligne
tr -d " \t\n"  <src  >dest

sed -r s/<regex>/<subst>∕g

Reproduit sur sa sortie standard le texte lu sur l'entrée standard, en remplaçant toutes les occurences de l'expression régulière par le texte <subst> (qui peut être vide).

Note

sed (serial editor) est en fait un éditeur de texte programmable. Ceci n'est qu'une des nombreuses instructions qu'il supporte.

Expressions régulières

Une expression régulière (ou regex) décrit dans une syntaxe spécialisée une famille de chaînes de caractères.

Par exemple :

  • a.*z : tout chaîne qui commence par a et se termine par z

  • [a-z]{1,5} : tous les mots de 1 à 5 lettres minuscules

  • \d{2}/\d{2}/\d{4} : toutes les dates au format jj/mm/aaaa (un peu plus)

  • [a-z0-9.-]+@[a-z0-9.-]+(\.[a-z]+)* : toutes les adresses e-mail (un peu moins)

Les expressions régulières sont également utilisables

  • dans la plupart les langages de programmation,

  • dans les fonctions de recherche avancée des éditeurs de texte,

  • ...

Caractères spéciaux

  • . : n'importe quel caractère

  • [...] : un caractère appartenant à la séquence décrite, exemples :

    • [xyz] : un des caractères x, y ou z

    • [^xyz] : n'importe quel caractère autre que x, y ou z

    • [0-9] : n'importe quel chiffre décimal

    • [a-zA-Z_] : n'importe quelle lettre minuscule ou majuscule, ou l'underscore.

  • ^ : le début de la ligne

  • $ : la fin de la ligne

Modificateurs

Si on suppose que a et b sont des expressions régulières quelconques :

  • (a)* : un texte qui satisfait a zéro fois ou plus

  • (a)+ : un texte qui satisfait a une fois ou plus

  • (a)? : un texte qui satisfait a zéro ou une fois

  • (a){i,j} : un texte qui satisfait a entre i et j fois

  • (a)|(b) : un texte qui satisfait a ou b

Échappements

Pour éviter que egrep ou sed n'interprète un caractère spécial on le fera précéder d'un antislash (\).

Exemple:

# affiche toutes les lignes de src qui contiennent un a suivi d'une étoile
egrep "a\*"  <src

Avertissement

  • Les expressions régulière sont très similaires aux méta-caractères du shell, à la fois dans leur objectif et dans leur syntaxe. Mais attention, il y a des différences de syntaxe (par exemple *).

  • À cause de cette similitude syntaxique, il est recommandé de toujours mettre les expressions régulières entre guillemets, pour éviter que le shell n'interprète les méta-caractères qu'elles contiennent...

  • En particulier, les anti-slash d'échappement destinés à egrep ou sed doivent eux-même être échappés pour ne pas être interprétés par le shell !

Tubes

Un tube (en anglais pipe) est un canal de communication quasi-synchrone entre deux programmes.

L'un des programmes écrit des données à une « extrémité » du tube ; l'autres les récupère en lisant à l'autres « extrémité ».

Contrairement à un fichier, les données écrites dans le tube ne sont pas stockées.

Création d'un tube en ligne de commande

En concaténant deux lignes de commandes, séparées par le caractère |, on demande au shell

  • de créer un tube,

  • d'exécuter le programme de gauche, après avoir redirigé sa sortie standard sur une extrémité, et

  • d'exécuter en parallèle le programme de droite, après avoir redirigé son entrée standard sur l'autre extrémité.

Le shell attend ensuite la fin des deux programmes.

# affiche les fichiers dont le nom est composé
# uniquement de minuscules ou uniquement de majuscules

ls | egrep "([a-z]+)|([A-Z]+)"

Une telle ligne de commande est appelée un pipeline.

Il est possible de concaténer plus de deux commandes ainsi.

# affiche les fichiers dont le nom a le format IMG_<numéro>.png
# triés par numéro

ls | egrep "IMG_[0-9]+.png" | sort -n -k2 -t_

Travaux dirigés

Exercice 1 : redirections

  1. Stockez, dans un fichier texte, la liste des fichiers et répertoires de votre répertoire d’accueil. Vérifiez que cela a fonctionné.

  2. Écrivez "fin" à la fin de ce fichier sans utiliser d'éditeur de texte.

  3. Enregistrez dans un fichier la page de manuel (man) de la commande ls.

Exercice 2 : filtres et expressions régulières (encore)

Récupérez le fichier fruits.txt.

Affichez :

  1. Les lignes dont le nom est "Fraise" ou "fraise"

  2. Les lignes ou "ai" est présent dans le nom

  3. Les lignes dont le nom se finit en "se"

  4. Les lignes dont le nom contient un chiffre

  5. Les lignes dont le nom fait exactement 5 caractères

Exercice 3 : filtres et expressions régulières

Récupérez le fichier contacts.txt. Chaque ligne de ce fichier comporte un nom, une ville et un numéro de téléphones, séparés par le caractère deux-points (:).

  1. Affichez uniquement les noms et numéros de téléphone de l’annuaire.

  2. Affichez les informations sur un correspondant connu par son nom.

  3. Affichez l’annuaire trié sur le nom.

  4. Constituez un nouvel annuaire contenant tous les correspondants sauf "Jean Dupont".

  5. Affichez le nombre de correspondants.

  6. Affichez les correspondants qui habitent Lyon.

  7. Affichez les correspondants dont le nom commence par "d".

Exercice 4: Dé-htmliseur

Enregistrez cette page Web dans votre répertoire home.

À l'aide d'une ligne de commande, créez un fichier qui contient le texte de ce ce fichier HTML, débarassé de toutes ses balises.