Bonsoir,
Quelqu'un peut-il m'expliquer pourquoi je n'obtiens pas le résultat attendu.
Je fais inévitablement une erreur de logique, sans comprendre laquelle…
$cat > fichier.txt
cool
pas cool
sympa
pas sympa
ctrl c
$tail -2 fichier.txt | nl fichier.txt
1 cool
2 pas cool
3 sympa
4 pas sympa
Résultat attendu :
$tail -2 fichier.txt | nl fichier.txt
3 sympa
4 pas sympa
Merci !
# logique...
Posté par BAud (site web personnel) . Évalué à 10 (+9/-0). Dernière modification le 26 août 2024 à 22:15.
essaie plutôt
# Qu'est-ce qu'un pipe ?
Posté par totof2000 . Évalué à 10 (+11/-0). Dernière modification le 26 août 2024 à 23:44.
Pour savoir exactement ce que ça fait, il faut savoir comment fonctionne un "tube", et connaitre le principe d'entrée et de sortie standard + erreur sous Unix.
Tout processus lorsqu'il est créé possède par défaut trois descripteurs de fichiers ouverts qui lui serviront à communiquer : l'entrée standard (le clavier pour un processus interactif dans un shell), la sortie standard (le terminal par défaut), et la sortie d'erreur (le terminal également). Petit exemple : exécute la commande cat sans rien lui passer : tu verras qu'elle t'affichera tout ce que tu lui entres au clavier:
Note : pour arrêter la saisie sur l'entrée standard, tu tapes sur les touches CTRL+D
En fait la commande cat est une commande qui, si on ne lui spécifie pas de paramètres, va prendre tout ce qui arrive sur l'entrée standard pour l'afficher sur la sortie standard (petite parenthèse : le nom cat vient à l'origine du mot con*cat*, et cette commande permet d'afficher sur sa sortie standard les fichiers qu'on lui passe en paramètre).
Le descripteur de fichier de l'entrée standard porte le numéro 0, celui de la sortie standard le numéro 1, et celui de la sortie d'erreur le numéro 2 (on y reviendra plus tard).
Cependant, il est possible de faire des redirections des divers périphériques par défaut. Par exemple, tu peux exécuter la commade cat < /dev/random : en exécutant cette commande tu dis à cat que l'entrée standard n'est plus le clavier, mais le fichier que tu as passé en paramètre (ici /dev/randpm génère des nombres aléatoires : tu verras une bouillie binaire s'afficher à ton écran).
De même qu'il est possible de changer le périphérique d'entrée, il est possible de changer le périphérique de sortie. Par exemple, si tu veux rediriger la sortie de la commande cat dans un fichier :
(taper control+d pour faire cesser la saisie)
Là tu as généré un fichier que tu peux visualiser ainsi :
Le troisième descripteur est la sortie d'erreur. Cette sortie affiche le message d'erreur. Faisons en sorte que cat génère une erreur en lui donnant un fichier bidon en paramètre d'entrée :
Une erreur qui s'affiche à l'écran, mais tu peux également la rediriger :
La commande est "muette", mais elle génère bien un message d'erreur qu'on a redirigé vers un fichier
Maintenant venons-en aux pipes. Quand tu enchaines les commandes via un pipe, tu demandes à ce que la sortie standard de la commande à gauche du pipe soit redirigée vers l'entrée standard de la commande à droite du pipe. Décomposons cet enchaînement :
Ici, la commande écho affiche sur la sortie standard la chaîne "coucou" et la commande cat la récupère depuis son entrée standard pour l'afficher à son tour sur sa sortie standard. A noter que les deux commandes tournent en parallèle. Le traitement de la commande de droite n'attend pas que la commande de gauche soit terminée pour s'exécuter. Elles tournent ensemble et les données sont traitées par la commande de droite au fur à mesure qu'elles arrivent de la commande de gauche.
En redirigeant vers un fichier :
Si tu veux récupérer la sortie standard et la sortie d'erreur pour la rediriger vers ton pipe tu peux : il suffit de le demander. Voici ce qui se passe sans redirection :
Le premier cat essaie de récpérer le contenu du fichier en paramètre, mais comme il n'existe pas, le processus affiche un message d'erreur. ( et si tu vas voir le contenu de /tmp/coucou.txt, tu auras un fichier vide car la commande n'a rien retourné sur sa sortie standard).
Si on veut récupérer ce message d'erreur dans le pipe, il faut rediriger la sortie d'erreur (descripteur N° 2) vers la sortie standard (2>&1 permet de le faire dans la commande suivante) :
Là encore, à la saisie on a l'impression qui ne se passe rien .. mais si on va voir :
Pour résumer, quand on exécute commmande 1 | commande 2, on demande à commande 2 de récupérer sur son entrée standard le contenu du canal de sortie standard de commande 1. Et si tu veux rediriger la sortie d'erreur vers le pipe, il faut que tu précises à la commande 1 (à gauche du pipe) de rediriger sa sortie d'erreur vers la sortie standard (je précise parce que c'est facile d'oublier).
Maintenant pourquoi ce que tu as fait n'a pas fonctionné ?
En gros tu dis à tail de récupérer les deux dernières lignes du fichier en paramètre. Tail les envoie sur sa sortie standard qui est capturée par le pipe. Sauf que à droite tu dis à la commande nl de ne pas récupérer la sortie standard, mais de récupérer les données du fichier passé en paramètre. Donc la sortie standard de la commande de gauche est ignorée. Tout ce que tu fais c'est exécuter des commandes en parallèle sans qu'elles n'interagissent entre elles.
Maintenant un petit mot : j'ai utilisé cat pour l'exemple. Cependant beaucoup de monde croit que faire un cat est nécessaire pour pouvoir ensuite le traiter par une autre commande (tu verras beaucoup de cat fichier | grep par exemple). Le cat ne sert à rien dans ce cas. Démonstration avec le fichier généré précédemment :
Beaucoup de gens vont faire ceci :
Le cat ne sert à rien. On appelle ça UUOC ou Useless use of cat. Dans ce cas il vaut mieux faire ceci:
Et si ta commande ne prend pas de fichier en paramètre mais ne prend ses données sur l'entrée standard (oui ça existe) :
[^] # Re: Qu'est-ce qu'un pipe ?
Posté par fearan . Évalué à 5 (+2/-0).
j'ajouterai qu'il y'a une autre erreur de logique qui va automatiquement se glisser après la première correction; la numérotation ne sera pas la bonne.
Il ne faut pas décorner les boeufs avant d'avoir semé le vent
[^] # Re: Qu'est-ce qu'un pipe ?
Posté par totof2000 . Évalué à 2 (+0/-0).
C'est à dire ?
[^] # Re: Qu'est-ce qu'un pipe ?
Posté par BAud (site web personnel) . Évalué à 3 (+1/-0). Dernière modification le 27 août 2024 à 13:17.
cf. explication —— v
[^] # Re: Qu'est-ce qu'un pipe ?
Posté par totof2000 . Évalué à 3 (+1/-0).
OK, je vois. Je ne m'étais pas intéressé à cet aspect. Je ne m'interessais qu'à l'explication sur les pipes. Mais c'est bien vu.
# explication
Posté par Tonton Th (Mastodon) . Évalué à 10 (+10/-0).
Pour arriver à ton résultat attendu, il faut numéroter les lignes avant d'extraire la partie que tu souhaites voir :
Et ne pas donner de nom de fichier à traiter à ta deuxième étape, pour qu'elle utilise son stdin (l'entrée standard) qui reçoit le résultat de la première étape.
# Petit détail
Posté par gUI (Mastodon) . Évalué à 9 (+6/-0).
Au tout début quand tu fais ton
tu le finis par un violent
CTRL-C
(tu tues la commandescat
). tu devrais plutôt le finir par unCTRL-D
qui est une fin de fichier qui dira donc àcat
"c'est bon c'est fini !".perso c'est d'ailleurs avec un
CTRL-D
que je ferme mes terminaux ("fin des commandes").En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.
# Normal, ...
Posté par audionuma (site web personnel, Mastodon) . Évalué à 4 (+4/-1).
# Top merci
Posté par Werber . Évalué à 1 (+0/-0).
Bonsoir à tous,
Ayant fait une petite pause dans mon apprentissage (vous l'aurez remarqué) de débutant. Sachez que j'étais de prime abord perdu…
Je reviens faire un peu de pratique journalière cette semaine.
J'ai pu apprécier énormément vos retours !
J'ai tout compris, s
Super explication totof2000. Je n'imaginais même pas que ce genre de chose était possible au sujet de la récupération d'erreur via le pipe (2>&1). D'ailleurs la syntaxe de ce genre de commande ne coule pas de source pour moi.. ou vous documentez vous pour ce genre de connaissance ?
En tout cas, j'ai bien rigolé en sentant que j'avais tout compris.
gUI, en me renseignant un peu plus, c'est vrai que c'est bourin ! Merci de ta remarque.
[^] # Re: Top merci
Posté par MicP . Évalué à 2 (+1/-0). Dernière modification le 02 septembre 2024 à 06:14.
Bonjour
Il y a les pages du manuel du shell bash,
et pour aller directement à la page du manuel concernant les redirections,
tu peux lancer la ligne de commande suivante :
Concernant les pipes,
la variable du shell bash PIPESTATUS pourrait aussi t'intéresser.
Voir aussi : Introduction à la programmation en Bash (Eric Sanchis)
Un lien vers la page concernant les redirections : Chapitre 5. Redirections élémentaires
[^] # Re: Top merci
Posté par Werber . Évalué à 1 (+0/-0).
Merci, je vais étudier tout ça
Envoyer un commentaire
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.