« Redirections bash » : différence entre les versions

De knowledge
Aller à la navigation Aller à la recherche
mAucun résumé des modifications
mAucun résumé des modifications
Ligne 16 : Ligne 16 :


Déjà, de façon, transparente ce clavier et cet écrans sont transformés dans le cas du ssh (ou du telnet). Dans ce cas les entrées sorties sont redirigées vers le réseau lui même ver le client ssh qui... finalement l'envoie à un clavier et un écran même si ce n'est pas celui de ma machine sur laquelle tourne le processus.
Déjà, de façon, transparente ce clavier et cet écrans sont transformés dans le cas du ssh (ou du telnet). Dans ce cas les entrées sorties sont redirigées vers le réseau lui même ver le client ssh qui... finalement l'envoie à un clavier et un écran même si ce n'est pas celui de ma machine sur laquelle tourne le processus.
Un exemple typique : un simple ls.<syntaxhighlight lang="bash">
$ ls -l
total 44
-rwxr-xr-x 1 jpinon jpinon 15960 Aug  5 21:48 hello
-rw-r--r-- 1 jpinon jpinon    84 Aug  5 21:48 hello.c
-rw-r--r-- 1 jpinon jpinon  797 Aug  5 21:48 hello.s
-rwxr-xr-x 1 jpinon jpinon 15968 Aug  5 21:50 helloworld
-rw-r--r-- 1 jpinon jpinon    63 Aug  5 21:50 helloworld.c
$ ls rrr
ls: cannot access 'rrr': No such file or directory
$
</syntaxhighlight>Le premier ls ci dessus envoie sa sortie standard vers l'écran (le flux en bleu sur le schéma). Dans le cas second ls, il s'agit d'une erreur donc vers la sortie d'erreur (flux en rouge).
Il est impossible, pour le moment, de savoir si ce qui est à l'écran a été envoyé vers la sortie standard ou la sortie d'erreur. (sauf le bon sens)
Pour le cas de l'entrée standard l'exemple est plus subtil, on va utiliser grep. grep est un programme assez simple (bon il a plein d'options mais on en parlera pas là) il lit l'entrée standard ligne par ligne et ne l'affiche sur la sortie que si elle comprends un chaine donnée en paramètre.<syntaxhighlight lang="bash">
$ grep toto
Bonjour toi
Bonjour vous
Hello toto
Hello toto
Ca va toto?
Ca va toto?
au revoir toto
au revoir toto
salut
</syntaxhighlight>le shell envoie aussi à l'écran ce que l'on tape au clavier avant de l'envoyer au programme (il appelle ca l'écho).
que se passe t'il dans notre exemple? On entre le ligne <code>"Bonjour toi"</code>. Le shell l'envoie à l'écran et au process (grep). grep lit la ligne<code>"Bonjour toi"</code>et vérifie si elle contient la chaine qu'on lui a donné en paramètre <code>"toto"</code>. Ce n'est pas le cas, grep ignore la ligne. Il se passe la même chose pour <code>"Bonjour vous"</code>. En revanche pour <code>"Hello toto"</code> le shell l'envoie a l'écran (echo) et à grep. Grep voit qu'elle contient bien la chaine <code>"toto",</code> alors elle écrit la ligne sur la sortie standard.
Donc on voit la ligne en double. D'abord l'echo de ce qu'on tape ensuite la sortie de grep.
== Redirections ==
L'un des concepts les puis puissant du shell unix (linux par la suite) est que ces 3 flux peuvent êtres branchées sur n'importe quoi d'autre (on vient d'effleurer le sujet avec ssh).
=== redirection entre process ===
c'est la redirection de la sortie d'un process vers l'entrée d'un autre. Ca s'appelle un 'pipe' (un tube, un tuyau... )
[[Fichier:Process-bash002.png|sans_cadre|916x916px]]
Pour chainer ainsi deux process on utilise le caractère "pipe" soit <code>"|"</code>.
Il s'agit d'une barre verticale qui semble être un tuyau dans le mauvais sens. Il faut connaitre comment les premières machines affichaient ce caractère : pas <code>"|"</code> mais <code>"¦"</code>.
Une barre avec un petit trou pour laisser passer le flux. Ce caractère à été simplifié et maintenant et on ne comprends plus bien.<syntaxhighlight lang="bash">
$ ls -l
total 44
-rwxr-xr-x 1 jpinon jpinon 15960 Aug  5 21:48 hello
-rw-r--r-- 1 jpinon jpinon    84 Aug  5 21:48 hello.c
-rw-r--r-- 1 jpinon jpinon  797 Aug  5 21:48 hello.s
-rwxr-xr-x 1 jpinon jpinon 15968 Aug  5 21:50 helloworld
-rw-r--r-- 1 jpinon jpinon    63 Aug  5 21:50 helloworld.c
$ ls -l | grep toto
$ ls -l | grep "c"
-rw-r--r-- 1 jpinon jpinon    84 Aug  5 21:48 hello.c
-rw-r--r-- 1 jpinon jpinon    63 Aug  5 21:50 helloworld.c
</syntaxhighlight>La première commande est un bête ls qui donne la liste des fichiers.
La seconde filtre ces lignes pour n'afficher que les lignes contenant la chaine <code>"toto"</code>.. c'est à dire aucune.
La troisième filtre les lignes pour n'afficher que celles contenant <code>"c"</code> c'est a dire deux d'entres elles.
Attention on parle là de flux de caractères. Les redirections et les process de ces exemples ne "comprennent" pas ce qu'on leur envoie dans les flux.
si on avait utilisé grep avec <code>"n":</code><syntaxhighlight lang="bash">
$ ls -l | grep "n"
-rwxr-xr-x 1 jpinon jpinon 15960 Aug  5 21:48 hello
-rw-r--r-- 1 jpinon jpinon    84 Aug  5 21:48 hello.c
-rw-r--r-- 1 jpinon jpinon  797 Aug  5 21:48 hello.s
-rwxr-xr-x 1 jpinon jpinon 15968 Aug  5 21:50 helloworld
-rw-r--r-- 1 jpinon jpinon    63 Aug  5 21:50 helloworld.c
</syntaxhighlight>Aucun fichier ne contient de <code>"n"</code> mais grep traite le flux ligne de texte par ligne de texte. Il trouve des <code>"n"</code> dans le nom du user et du groupe il affiche la ligne.
Nous ne sommes pas dans des shell type powershell qui traitent des objets. Ici on traite des flux de caractres est bête et méchants.
=== Les types de redirections ===
==== Fichiers ====
==== ">" Rediriger la sortie standard vers un fichier ====
Autant <code>"|"</code> dirige la sortie d'un processus vers l'entrée d'un autre processus <code>">"</code> redirige simplement la sortie standard d'un process vers un fichier disque.
Exemple simple un simple ls.<syntaxhighlight lang="bash">
$ ls -l
total 44
-rwxr-xr-x 1 jpinon jpinon 15960 Aug  5 21:48 hello
-rw-r--r-- 1 jpinon jpinon    84 Aug  5 21:48 hello.c
-rw-r--r-- 1 jpinon jpinon  797 Aug  5 21:48 hello.s
-rwxr-xr-x 1 jpinon jpinon 15968 Aug  5 21:50 helloworld
-rw-r--r-- 1 jpinon jpinon    63 Aug  5 21:50 helloworld.c
</syntaxhighlight>La commande ls envoie la liste des fichier vers la sortie standard. Jusque là on n'a rien fait!<syntaxhighlight lang="bash">$ ls -l > resultat.txt</syntaxhighlight>Cette commande ne réponds rien et c'est normal. On lui a demandé de rediriger la sortie standard vers un fichier <code>"resultat.txt"</code>
Si on refait un ls.<syntaxhighlight lang="bash">$ ls -l
total 48
-rwxr-xr-x 1 jpinon jpinon 15960 Aug  5 21:48 hello
-rw-r--r-- 1 jpinon jpinon    84 Aug  5 21:48 hello.c
-rw-r--r-- 1 jpinon jpinon  797 Aug  5 21:48 hello.s
-rwxr-xr-x 1 jpinon jpinon 15968 Aug  5 21:50 helloworld
-rw-r--r-- 1 jpinon jpinon    63 Aug  5 21:50 helloworld.c
-rw-r--r-- 1 jpinon jpinon  344 Aug  5 23:21 resultat.txt</syntaxhighlight>Effectivement on a un nouveau fichier!
SI on regarde ce qu'il i a dedans (cat, vi, nano... chacun sa méthode) mais on y trouve :<syntaxhighlight lang="text">
-rwxr-xr-x 1 jpinon jpinon 15960 Aug  5 21:48 hello
-rw-r--r-- 1 jpinon jpinon    84 Aug  5 21:48 hello.c
-rw-r--r-- 1 jpinon jpinon  797 Aug  5 21:48 hello.s
-rwxr-xr-x 1 jpinon jpinon 15968 Aug  5 21:50 helloworld
-rw-r--r-- 1 jpinon jpinon    63 Aug  5 21:50 helloworld.c
-rw-r--r-- 1 jpinon jpinon    0 Aug  5 23:21 resultat.txt
</syntaxhighlight>On remarque que <code>"resultat.txt"</code> est déjà dedans mais avec une taille nulle. Etrange? pas tant que ça et ca nous montre bien comment ça se passe.
Lors de la commande  <code>"ls -l > resultat.txt"</code>  le shell (bash ici) voit que la sortie de <code>ls</code> devra aller dans un fichier <code>"resultat.txt"</code> qu'il s'empresse de créer mais, pour le moment, il est vide. Le shell lance alors le <code>"ls -l"</code> qui fait la liste des fichiers, dont resultat.txt qui est vide, et l'envoie dans le fichier "resultat.txt" qui se remplis alors.
A la sortie resultat.txt est donc plein mais, quand il a été lut par ls il était vide!
'''Tout est simple et logique en bash!'''
==== "<" rediriger un fichier vers l'entrée standard d'un process. ====
C'est la partie la moins élégante de la syntaxe je trouve mais bon. On peut utiliser un fichier comme l'entrée d'un process.
C'est assez rarement utilisé parce que'à la fois pas clair et pas très utile. Suivez moi bien:<syntaxhighlight lang="bash">
cat
</syntaxhighlight>affiche le résultat  de l'entrée standard sur la sortie standard. Le truc le plus inutile possible!<syntaxhighlight lang="bash">
$ cat
hello
hello
bonjour
bonjour
jaquot
jaquot
blabla
blabla
</syntaxhighlight>Ca répète tout ce qu'on tape jusqu'à la fin du texte (EOF<!-- EOF = End of file (fin du fichier) --> ou <Ctrl> D)
si on voulait lui faire écrire ce qu'il y a dans un fichier on sait qu'il faut faire :<syntaxhighlight lang="bash">
cat resultat.txt
</syntaxhighlight>Ca marche mais c'est pas ce que je veux vous montrer. C'est juste le fonctionnement de la commande <code>cat</code>. SI on lui donne un paramètre au lieu de copier l'entrée standard elle prends le paramètre en question, ouvre le fichier disque qui correspond de l'envoie sur la sortie standard. Là c'est le programme <code>cat</code> qui fait le travail.
Si on fait :<syntaxhighlight lang="bash">cat < resultat.txt # Attention un < s'est introduit dans cette commande!</syntaxhighlight>le résultat est exactement le même mais les actions effectuées sont totalement différentes!
Que fait le shell?
* Il ouvre <code>cat</code> sans paramètres qui va alors lire les lignes une par une sur l'entrée standard et les envoyer sur la sortie standard jusqu'à EOF. Il est bête mais on lui en demande pas plus.
* Mais le shell vois aussi que l'entrée standard de cat doit être "alimentée", non pas par le clavier mais par le contenu d'un fichier "resultat.txt"
* doc cat prends ce qu'il a en entrée (le shell lui envoie le contenu de resultat.txt) et l'envoie sur la sortie standard (ici l'écran)
On pourrait envisager un:<syntaxhighlight lang="bash">
cat < resultat.txt > resultat1.txt
</syntaxhighlight>...qui en fait est l'équivalant d'une copie de <code>resultat.txt</code> vers <code>resultat1.txt</code>.<syntaxhighlight lang="bash">
cp resultat1 resultat2
</syntaxhighlight>aurait fait pareil.
Encore plus pervère<syntaxhighlight lang="bash">
cat < resultat.txt | grep jpinon > resultat2.txt
</syntaxhighlight>Le shell traite comme ça:
* ouverture de <code>cat</code> "tout nu" qui lit sur l'entrée et envoie vers la sortie
* son entrée est connectée par shell sur le fichier <code>resultat.txt</code>. Ok, donc cat ne le sait pas mais il lit les lignes de <code>resultat.txt</code> une par une (c'est le shell qui les lui envoie).
* <code>cat</code> ecrit vers sa sortie standars mais le shell la redirrige vers <code>grep</code>.
* <code>grep</code> est presque aussi bête que <code>cat</code>. Il lit des lignes sur son entrée standard et les sort sur la sur la sortie standard pour peu que la ligne contienne la chaine en paramètre
* mais le shell est malin, il lui envoie sur son entrée standard la sortie de <code>cat</code>.
* a la fin le shell détourne la sortie de <code>grep</code> vers <code>resultat2.txt</code>
Tout ca se résume dans :
[[Fichier:Process-bash004.png|sans_cadre|914x914px]]
==== Remarque sur l'usage de "-" ====
Quelquefois il est indispensable de donner un fichier à une commande. dans ce cas là on peut remplacer ne nom du fichier par <code>"-"</code>.
Par exemple :<syntaxhighlight lang="bash">
cat -
</syntaxhighlight>est équivalant à:<syntaxhighlight lang="bash">
cat
</syntaxhighlight>bon pas très utile. Mais pensons au compilateur cc. une option est de lui demander de juste s'arreter au code assembleur mais pas d'aller jusqu'au code machine.<syntaxhighlight lang="bash">
cc -S hello.c
</syntaxhighlight>va, par défaut nous sortir un fichier hello.s qui contient le code assembleur. Imaginons que l'on veuille avoir ce code assembleur pour l'envoyer à un ami mais on le voudrait "gzippé". Problème cc sait sortir dans un fichier texte, on peut lui donner le nom du fichier de sortie par l'option "-o fichier.s" mais il ne sait pas zipper.
On porait faire ça en deux commandes :<syntaxhighlight lang="bash">
cc -o code.s -S hello.c
gzip code.s
</syntaxhighlight>en sortie on aura un fichier code.s.gz tres bien mais on a appris a faire des redirections! Alors on en fait!<syntaxhighlight lang="bash">cc -o - -S hello.c | gzip > code.s.gz</syntaxhighlight>C'est pas beau!
Avec un beau dessin :
[[Fichier:Process-bash005.png|sans_cadre|916x916px]]
On pourrait même l'envoyer directement à notre amis. Ce fichier code.s.gz j'en ai pas besoin moi!<syntaxhighlight lang="bash">
cc -o - -S hello.c | gzip | mail -s "le code assembleur de hello.c" monami@gmail.com
</syntaxhighlight>[[Fichier:Process-bash006.png|sans_cadre|916x916px]]
Bon comme ça ca parait un peu inutile mais imaginez une tâche [[cron]] qui lance, tous les jours à 4h le matin la commande suivante:<syntaxhighlight lang="bash">
df -h | mail -s "Etat des disques" moi@mondomaine.fr
</syntaxhighlight>Et oui! tous les matin j'aurais l'état de remplissage des disque de ma machine dans mes mails. On pourrait améliorer avec un <code>grep</code> entre <code>df</code> et <code>mail</code> pour ne mentionner que les disques qui posent un problème.

Version du 5 août 2026 à 22:49

Les redirections c'est la base des batches !

Echanges standard entre un process et son environnement.

Un process (process ou processus en français j'utiliserais les deux mots indéférament) est une suite d'instructions qui sont exécutées par le système les unes après les autres. Il n'y a pas de notion de parallélisme à ce niveau.

A sa création un process possède trois "flux" standard.

  • Une entrée
  • deux sorties (normal et erreurs)

Si rien n'est précisé l'entrée standard est le clavier et les deux sorties (standard et erreur sont l'écran)

Déjà, de façon, transparente ce clavier et cet écrans sont transformés dans le cas du ssh (ou du telnet). Dans ce cas les entrées sorties sont redirigées vers le réseau lui même ver le client ssh qui... finalement l'envoie à un clavier et un écran même si ce n'est pas celui de ma machine sur laquelle tourne le processus.

Un exemple typique : un simple ls.

$ ls -l
total 44
-rwxr-xr-x 1 jpinon jpinon 15960 Aug  5 21:48 hello
-rw-r--r-- 1 jpinon jpinon    84 Aug  5 21:48 hello.c
-rw-r--r-- 1 jpinon jpinon   797 Aug  5 21:48 hello.s
-rwxr-xr-x 1 jpinon jpinon 15968 Aug  5 21:50 helloworld
-rw-r--r-- 1 jpinon jpinon    63 Aug  5 21:50 helloworld.c
$ ls rrr
ls: cannot access 'rrr': No such file or directory
$

Le premier ls ci dessus envoie sa sortie standard vers l'écran (le flux en bleu sur le schéma). Dans le cas second ls, il s'agit d'une erreur donc vers la sortie d'erreur (flux en rouge).

Il est impossible, pour le moment, de savoir si ce qui est à l'écran a été envoyé vers la sortie standard ou la sortie d'erreur. (sauf le bon sens)

Pour le cas de l'entrée standard l'exemple est plus subtil, on va utiliser grep. grep est un programme assez simple (bon il a plein d'options mais on en parlera pas là) il lit l'entrée standard ligne par ligne et ne l'affiche sur la sortie que si elle comprends un chaine donnée en paramètre.

$ grep toto
Bonjour toi
Bonjour vous
Hello toto
Hello toto
Ca va toto?
Ca va toto?
au revoir toto
au revoir toto
salut

le shell envoie aussi à l'écran ce que l'on tape au clavier avant de l'envoyer au programme (il appelle ca l'écho).

que se passe t'il dans notre exemple? On entre le ligne "Bonjour toi". Le shell l'envoie à l'écran et au process (grep). grep lit la ligne"Bonjour toi"et vérifie si elle contient la chaine qu'on lui a donné en paramètre "toto". Ce n'est pas le cas, grep ignore la ligne. Il se passe la même chose pour "Bonjour vous". En revanche pour "Hello toto" le shell l'envoie a l'écran (echo) et à grep. Grep voit qu'elle contient bien la chaine "toto", alors elle écrit la ligne sur la sortie standard.

Donc on voit la ligne en double. D'abord l'echo de ce qu'on tape ensuite la sortie de grep.

Redirections

L'un des concepts les puis puissant du shell unix (linux par la suite) est que ces 3 flux peuvent êtres branchées sur n'importe quoi d'autre (on vient d'effleurer le sujet avec ssh).

redirection entre process

c'est la redirection de la sortie d'un process vers l'entrée d'un autre. Ca s'appelle un 'pipe' (un tube, un tuyau... ) Pour chainer ainsi deux process on utilise le caractère "pipe" soit "|". Il s'agit d'une barre verticale qui semble être un tuyau dans le mauvais sens. Il faut connaitre comment les premières machines affichaient ce caractère : pas "|" mais "¦".

Une barre avec un petit trou pour laisser passer le flux. Ce caractère à été simplifié et maintenant et on ne comprends plus bien.

$ ls -l
total 44
-rwxr-xr-x 1 jpinon jpinon 15960 Aug  5 21:48 hello
-rw-r--r-- 1 jpinon jpinon    84 Aug  5 21:48 hello.c
-rw-r--r-- 1 jpinon jpinon   797 Aug  5 21:48 hello.s
-rwxr-xr-x 1 jpinon jpinon 15968 Aug  5 21:50 helloworld
-rw-r--r-- 1 jpinon jpinon    63 Aug  5 21:50 helloworld.c
$ ls -l | grep toto
$ ls -l | grep "c"
-rw-r--r-- 1 jpinon jpinon    84 Aug  5 21:48 hello.c
-rw-r--r-- 1 jpinon jpinon    63 Aug  5 21:50 helloworld.c

La première commande est un bête ls qui donne la liste des fichiers.

La seconde filtre ces lignes pour n'afficher que les lignes contenant la chaine "toto".. c'est à dire aucune. La troisième filtre les lignes pour n'afficher que celles contenant "c" c'est a dire deux d'entres elles.

Attention on parle là de flux de caractères. Les redirections et les process de ces exemples ne "comprennent" pas ce qu'on leur envoie dans les flux.

si on avait utilisé grep avec "n":

$ ls -l | grep "n"
-rwxr-xr-x 1 jpinon jpinon 15960 Aug  5 21:48 hello
-rw-r--r-- 1 jpinon jpinon    84 Aug  5 21:48 hello.c
-rw-r--r-- 1 jpinon jpinon   797 Aug  5 21:48 hello.s
-rwxr-xr-x 1 jpinon jpinon 15968 Aug  5 21:50 helloworld
-rw-r--r-- 1 jpinon jpinon    63 Aug  5 21:50 helloworld.c

Aucun fichier ne contient de "n" mais grep traite le flux ligne de texte par ligne de texte. Il trouve des "n" dans le nom du user et du groupe il affiche la ligne.

Nous ne sommes pas dans des shell type powershell qui traitent des objets. Ici on traite des flux de caractres est bête et méchants.

Les types de redirections

Fichiers

">" Rediriger la sortie standard vers un fichier

Autant "|" dirige la sortie d'un processus vers l'entrée d'un autre processus ">" redirige simplement la sortie standard d'un process vers un fichier disque.

Exemple simple un simple ls.

$ ls -l
total 44
-rwxr-xr-x 1 jpinon jpinon 15960 Aug  5 21:48 hello
-rw-r--r-- 1 jpinon jpinon    84 Aug  5 21:48 hello.c
-rw-r--r-- 1 jpinon jpinon   797 Aug  5 21:48 hello.s
-rwxr-xr-x 1 jpinon jpinon 15968 Aug  5 21:50 helloworld
-rw-r--r-- 1 jpinon jpinon    63 Aug  5 21:50 helloworld.c

La commande ls envoie la liste des fichier vers la sortie standard. Jusque là on n'a rien fait!

$ ls -l > resultat.txt

Cette commande ne réponds rien et c'est normal. On lui a demandé de rediriger la sortie standard vers un fichier "resultat.txt" Si on refait un ls.

$ ls -l
total 48
-rwxr-xr-x 1 jpinon jpinon 15960 Aug  5 21:48 hello
-rw-r--r-- 1 jpinon jpinon    84 Aug  5 21:48 hello.c
-rw-r--r-- 1 jpinon jpinon   797 Aug  5 21:48 hello.s
-rwxr-xr-x 1 jpinon jpinon 15968 Aug  5 21:50 helloworld
-rw-r--r-- 1 jpinon jpinon    63 Aug  5 21:50 helloworld.c
-rw-r--r-- 1 jpinon jpinon   344 Aug  5 23:21 resultat.txt

Effectivement on a un nouveau fichier! SI on regarde ce qu'il i a dedans (cat, vi, nano... chacun sa méthode) mais on y trouve :

-rwxr-xr-x 1 jpinon jpinon 15960 Aug  5 21:48 hello
-rw-r--r-- 1 jpinon jpinon    84 Aug  5 21:48 hello.c
-rw-r--r-- 1 jpinon jpinon   797 Aug  5 21:48 hello.s
-rwxr-xr-x 1 jpinon jpinon 15968 Aug  5 21:50 helloworld
-rw-r--r-- 1 jpinon jpinon    63 Aug  5 21:50 helloworld.c
-rw-r--r-- 1 jpinon jpinon     0 Aug  5 23:21 resultat.txt

On remarque que "resultat.txt" est déjà dedans mais avec une taille nulle. Etrange? pas tant que ça et ca nous montre bien comment ça se passe.

Lors de la commande "ls -l > resultat.txt" le shell (bash ici) voit que la sortie de ls devra aller dans un fichier "resultat.txt" qu'il s'empresse de créer mais, pour le moment, il est vide. Le shell lance alors le "ls -l" qui fait la liste des fichiers, dont resultat.txt qui est vide, et l'envoie dans le fichier "resultat.txt" qui se remplis alors.

A la sortie resultat.txt est donc plein mais, quand il a été lut par ls il était vide!

Tout est simple et logique en bash!

"<" rediriger un fichier vers l'entrée standard d'un process.

C'est la partie la moins élégante de la syntaxe je trouve mais bon. On peut utiliser un fichier comme l'entrée d'un process.

C'est assez rarement utilisé parce que'à la fois pas clair et pas très utile. Suivez moi bien:

cat

affiche le résultat de l'entrée standard sur la sortie standard. Le truc le plus inutile possible!

$ cat
hello
hello
bonjour
bonjour
jaquot
jaquot
blabla
blabla

Ca répète tout ce qu'on tape jusqu'à la fin du texte (EOF ou <Ctrl> D) si on voulait lui faire écrire ce qu'il y a dans un fichier on sait qu'il faut faire :

cat resultat.txt

Ca marche mais c'est pas ce que je veux vous montrer. C'est juste le fonctionnement de la commande cat. SI on lui donne un paramètre au lieu de copier l'entrée standard elle prends le paramètre en question, ouvre le fichier disque qui correspond de l'envoie sur la sortie standard. Là c'est le programme cat qui fait le travail. Si on fait :

cat < resultat.txt # Attention un < s'est introduit dans cette commande!

le résultat est exactement le même mais les actions effectuées sont totalement différentes!

Que fait le shell?

  • Il ouvre cat sans paramètres qui va alors lire les lignes une par une sur l'entrée standard et les envoyer sur la sortie standard jusqu'à EOF. Il est bête mais on lui en demande pas plus.
  • Mais le shell vois aussi que l'entrée standard de cat doit être "alimentée", non pas par le clavier mais par le contenu d'un fichier "resultat.txt"
  • doc cat prends ce qu'il a en entrée (le shell lui envoie le contenu de resultat.txt) et l'envoie sur la sortie standard (ici l'écran)

On pourrait envisager un:

cat < resultat.txt > resultat1.txt

...qui en fait est l'équivalant d'une copie de resultat.txt vers resultat1.txt.

cp resultat1 resultat2

aurait fait pareil. Encore plus pervère

cat < resultat.txt | grep jpinon > resultat2.txt

Le shell traite comme ça:

  • ouverture de cat "tout nu" qui lit sur l'entrée et envoie vers la sortie
  • son entrée est connectée par shell sur le fichier resultat.txt. Ok, donc cat ne le sait pas mais il lit les lignes de resultat.txt une par une (c'est le shell qui les lui envoie).
  • cat ecrit vers sa sortie standars mais le shell la redirrige vers grep.
  • grep est presque aussi bête que cat. Il lit des lignes sur son entrée standard et les sort sur la sur la sortie standard pour peu que la ligne contienne la chaine en paramètre
  • mais le shell est malin, il lui envoie sur son entrée standard la sortie de cat.
  • a la fin le shell détourne la sortie de grep vers resultat2.txt

Tout ca se résume dans :

Remarque sur l'usage de "-"

Quelquefois il est indispensable de donner un fichier à une commande. dans ce cas là on peut remplacer ne nom du fichier par "-".

Par exemple :

cat -

est équivalant à:

cat

bon pas très utile. Mais pensons au compilateur cc. une option est de lui demander de juste s'arreter au code assembleur mais pas d'aller jusqu'au code machine.

cc -S hello.c

va, par défaut nous sortir un fichier hello.s qui contient le code assembleur. Imaginons que l'on veuille avoir ce code assembleur pour l'envoyer à un ami mais on le voudrait "gzippé". Problème cc sait sortir dans un fichier texte, on peut lui donner le nom du fichier de sortie par l'option "-o fichier.s" mais il ne sait pas zipper. On porait faire ça en deux commandes :

cc -o code.s -S hello.c
gzip code.s

en sortie on aura un fichier code.s.gz tres bien mais on a appris a faire des redirections! Alors on en fait!

cc -o - -S hello.c | gzip > code.s.gz

C'est pas beau!

Avec un beau dessin :

On pourrait même l'envoyer directement à notre amis. Ce fichier code.s.gz j'en ai pas besoin moi!

cc -o - -S hello.c | gzip | mail -s "le code assembleur de hello.c" monami@gmail.com

Bon comme ça ca parait un peu inutile mais imaginez une tâche cron qui lance, tous les jours à 4h le matin la commande suivante:

df -h | mail -s "Etat des disques" moi@mondomaine.fr

Et oui! tous les matin j'aurais l'état de remplissage des disque de ma machine dans mes mails. On pourrait améliorer avec un grep entre df et mail pour ne mentionner que les disques qui posent un problème.