Les tuyaux (pipes) ou pipelines permettent de combiner des programmes en connectant la sortie de l'un à l'entrée de l'autre. Le terme "sortie" a une signification particulière ici : il s'agit de tout ce que le programme écrit vers la sortie standard, utilisant la fonction C printf ou tout autre équivalent, et qui apparaît normalement à l'écran. De même, "l'entrée" est l'entrée standard, venant normalement du clavier. Les pipelines sont construits en utilisant la barre verticale ("|") comme connecteur.
Imaginons que vous aidiez votre excentrique tante Hortense à gérer sa collection privée de livres. Vous avez un fichier nommé books contenant la liste de ses avoirs, un par ligne, dans le format "auteur:titre". Quelque chose comme :
$ cat books Carroll, Lewis:Through the Looking-Glass Shakespeare, William:Hamlet Bartlett, John:Familiar Quotations Mill, John Stuart:On Nature London, Jack:John Barleycorn Bunyan, John:Pilgrim's Progress, The Defoe, Daniel:Robinson Crusoe Mill, John Stuart:System of Logic, A Milton, John:Paradise Lost Johnson, Samuel:Lives of the Poets Shakespeare, William:Julius Caesar Mill, John Stuart:On Liberty Bunyan, John:Saved by Grace
Tout cela est un peu désordonné : la liste ne possède aucun ordre particulier. Nous pouvons utiliser la commande sort
pour arranger cela.
$ sort books Bartlett, John:Familiar Quotations Bunyan, John:Pilgrim's Progress, The Bunyan, John:Saved by Grace Carroll, Lewis:Through the Looking-Glass Defoe, Daniel:Robinson Crusoe Johnson, Samuel:Lives of the Poets London, Jack:John Barleycorn Mill, John Stuart:On Liberty Mill, John Stuart:On Nature Mill, John Stuart:System of Logic, A Milton, John:Paradise Lost Shakespeare, William:Hamlet Shakespeare, William:Julius Caesar
Bien, nous avons une belle liste triée par auteur. Comment obtenir uniquement la liste des auteurs sans les titres ? La commande cut
permet cela :
$ cut -d: -f1 books Carroll, Lewis Shakespeare, William Bartlett, John Mill, John Stuart London, Jack Bunyan, John Defoe, Daniel Mill, John Stuart Milton, John Johnson, Samuel Shakespeare, William Mill, John Stuart Bunyan, John
Une petite explication s'impose. L'option -d
choisit le double point comme séparateur (delimiter). Ce qui demande à cut
de couper chaque ligne là où le séparateur apparaît. Chaque partie ainsi séparée s'appelle un champ (field). De la manière dont notre fichier est organisé, le nom de l'auteur apparaît comme premier champ, nous avons donc passé un 1 à l'option -f
pour indiquer à cut
que nous sommes uniquement intéressé par ce champ.
Mais vous remarquerez que la liste n'est plus triée. Les pipelines à la rescousse!
$ sort books | cut -d: -f1 Bartlett, John Bunyan, John Bunyan, John Carroll, Lewis Defoe, Daniel Johnson, Samuel London, Jack Mill, John Stuart Mill, John Stuart Mill, John Stuart Milton, John Shakespeare, William Shakespeare, William
Voila! Partant d'une liste triée par ordre alphabétique, qui est le résultant de la commande sort
, vous l'avez transmise comme entrée à la commande cut
. Il ne faut pas donner un nom de fichier à la commande cut
, car vous désirez qu'elle traite le texte qui est produit par la commande sort
.
Les pipelines ne sont pas plus compliqués que cela--le texte passe d'une commande à l'autre à travers le pipeline.
Que faire si vous voulez plutôt une liste triée des titres ? Le titre étant le deuxième champ, tentons d'utiliser la commande cut
avec l'option -f2 plutôt que -f1
:
$ sort books | cut -d: -f2 Familiar Quotations Pilgrim's Progress, The Saved by Grace Through the Looking-Glass Robinson Crusoe Lives of the Poets John Barleycorn On Liberty On Nature System of Logic, A Paradise Lost Hamlet Julius Caesar
Oups. Que s'est-il passé? Lorsque vous étudiez un pipeline, vous devez aller de gauche à droite. Dans le cas qui nous occupe, nous trions la liste avant d'extraire les titres. Les lignes ont ainsi été diligemment triées mais elles commencent par le nom de l'auteur. Pour obtenir les titres dans l'ordre correct, il faut les trier après les avoir extraits :
$ cut -d: -f2 books | sort Familiar Quotations Hamlet John Barleycorn Julius Caesar Lives of the Poets On Liberty On Nature Paradise Lost Pilgrim's Progress, The Robinson Crusoe Saved by Grace System of Logic, A Through the Looking-Glass
Voilà qui est bien mieux. Tout ceci est bien joli, mais vous pensez peut-être que vous auriez pu obtenir le même résultat avec une feuille de calcul. Dans les cas simples, c'est probablement vrai. Mais supposons que Tante Hortense ait l'habitude de poser des questions bizarres au sujet de sa collection. Elle désire, par exemple, savoir combien de livres elle possède dont l'auteur est nommé John. Une feuille de calcul ou tout autre programme graphique aura probablement des difficultés à traiter toute requête qui n'a pas été anticipée par ses auteurs. Le shell, par contre, nous offre de nombreuses petites commandes simples qui peuvent être combinées pour accomplir des tâches complexes.
Pour trouver une chaîne particulière dans une ligne de texte, utilisez la commande grep
. Souvenez-vous que lorsque vous combinez des commandes, elles doivent être dans le bon ordre. Il ne faut pas exécuter grep
sur le fichier de départ, car elle trouverait le titre "John Barleycorn" en plus des auteurs nommés John. Il faut donc la placer à la fin du pipeline:
$ cut -d: -f1 books | sort | grep "John" Bartlett, John Bunyan, John Bunyan, John Johnson, Samuel Mill, John Stuart Mill, John Stuart Mill, John Stuart Milton, John
On se rapproche de la solution, mais nous ne voulons pas "Samuel Johnson" dans la liste parce que cela déplaît à Tante Hortense. Souvent, en utilisant grep,
vous devrez préciser le texte que vous recherche pour obtenir ce dont vous avez besoin. grep
dispose de l'option -w
qui ne trouvera "John" seulement lorsque "John" est un mot complet et non lorsqu'il fait partie de "Johnson". Mais non résoudrons ce problème particulier en ajoutant une virgule et un espace devant la chaîne que nous cherchons, ainsi elle ne correspondra à John que lorsqu'il apparaît comme prénom :
$ cut -d: -f1 books | sort | grep ", John" Bartlett, John Bunyan, John Bunyan, John Mill, John Stuart Mill, John Stuart Mill, John Stuart Milton, John
C'est mieux. Mais vous ne voulez que le nombre total de livres pour chacun des auteurs. Le petite commande nommé uniq
fera parfaitement l'affaire. Elle supprime les lignes doubles (les doublons doivent être sur des lignes successives, il faut donc s'assurer que le texte est d'abord triés), et lorsque l'option -c
est utilisée, elle compte le nombre de répétitions :
$ cut -d: -f1 books | sort | grep ", John" | uniq -c 1 Bartlett, John 2 Bunyan, John 3 Mill, John Stuart 1 Milton, JohnNous y sommes! Une liste de Johns proprement triée et le nombre de livres que chacun a écrit. Dans l'exemple qui nous occupe, cette opération est facile, on pourrait même le faire avec un crayon et du papier. Mais exactement le même pipeline peut être utilisé pour traiter de bien plus grande quantité de données -- il ne rechignera pas même si Tante Hortense a des centaines de milliers de livres stockées dans la grange.
Les administrateurs systèmes utilisent souvent des pipelines similaires pour traiter des fichiers de trace générés sur le web ou par des serveurs mail. De tels fichiers peuvent croître jusqu'à plusieurs dizaines ou centaines de mégabytes, et un pipeline de commande permet de générer rapidement des statistiques sans devoir lire la totalité de la trace.
Une bonne chose lorsqu'on est en train de définir des pipelines est que vous le faire commande par commande et voir exactement l'effet que chacune a sur le résultat. Cela vous aidera pour trouver quand il est nécessaire de changer les options ou réarranger les commandes. Par exemple, pour obtenir les auteurs prénommés John par ordre décroissant du nombre de livre en possession de Tante Hortense, il suffit d'ajouter sort -nr
au pipeline précédant :
$ cut -d: -f1 books | sort | grep ", John" | uniq -c | sort -nr 3 Mill, John Stuart 2 Bunyan, John 1 Milton, John 1 Bartlett, John
Expérimentez!
Il y a une erreur de communication avec le serveur Booktype. Nous ne savons pas actuellement où est le problème.
Vous devriez rafraîchir la page.