Commande Pipe couplée avec la commande cat

Ton fichier t1.txt est bien vide, comme l’a écrit MicP, mais cat concatène ce fichier (vide) avec l’erreur standard de la commande rm

michel@deb114x:~$ echo "contenu de t1.txt" > t1.txt
michel@deb114x:~$ echo "contenu de t2.txt" > t2.txt
michel@deb114x:~$ cat t1.txt t2.txt
contenu de t1.txt
contenu de t2.txt
michel@deb114x:~$ rm -v . .. 1> t1.txt | cat t2.txt
contenu de t2.txt
rm: impossible de supprimer '.': est un dossier
rm: impossible de supprimer '..': est un dossier
michel@deb114x:~$ cat t1.txt
michel@deb114x:~$ cat t2.txt
contenu de t2.txt
michel@deb114x:~$ 

ok , voilà l’explication = concaténation . 1&2 en somme . J’ai vu passer un truc comme ça dans une page sur ces fichiers virtuels . Je n’avais pas du tout compris la 1ère réponse de @MicP .

merci bien pour la réponse .

Tout à fait.
Le contenu de t1.txt est écrasé par la sortie standard (vide) de la commande rm. Et cat concatène ensuite t2 avec l’erreur standard de la commande rm

je viens enfin de comprendre cette réserve .

merci pour ces explications .

du manuel à propos de la commande cat :

DESCRIPTION
Concaténer le ou les FICHIER(s) sur la sortie standard.

   L'entrée  standard  est  lue  quand  FICHIER est omis ou quand FICHIER vaut
   « - ».

que signifie le tiret (?) « - » dans ce contexte ?

Il me semble que ton problème vient (entre autres) de l’utilisation du pipe avec les redirections. Ce qui n’a pas l’air trivial à part pour stdout.
Tu peux lire cette page, c’est intéressant (et pas simple).
Il y est dit que :

Le stdin du côté droit du pipe ‹ | › prend toujours sa source du stdout du côté gauche

Et donc si je comprends bien, quand tu tapes :

rm . .. 2>t.txt | cat t.txt

Il n’y a rien dans le stdout du côté gauche, et donc le pipe ne peut fonctionner. De plus, si tu cherches à enchaîner deux commandes, ce n’est pas un pipe (|) qu’il faut utiliser, mais un point-virgule (:wink: :

rm . .. 2>t.txt ; cat t.txt

Et là ça fonctionne.

1 J'aime

effectivement ça n’a pas l’air évident évident et je vais laisser ça de côté car de toute façon ces fichiers virtuels ne me sont pas du tout indispensables : je connais leur existence et ça suffira .

en conclusion : pour tester ces deux commandes c’était l’exemple à ne surtout pas choisir . pff…
merci pour l’info .

Dans ce contexte, le tiret représente l’entrée standard :

michel@deb114x:~$ echo "contenu de t1.txt" > t1.txt
michel@deb114x:~$ echo "t2.txt vers stdin de la commande qui sera après le pipe => sera remplacé par le tiret" > t2.txt
michel@deb114x:~$ cat t1.txt
contenu de t1.txt
michel@deb114x:~$ cat t2.txt
t2.txt vers stdin de la commande qui sera après le pipe => sera remplacé par le tiret
michel@deb114x:~$ #############################################
michel@deb114x:~$ 
michel@deb114x:~$ cat t2.txt | cat t1.txt
contenu de t1.txt
michel@deb114x:~$ 
michel@deb114x:~$ cat t2.txt | cat
t2.txt vers stdin de la commande qui sera après le pipe => sera remplacé par le tiret
michel@deb114x:~$ 
michel@deb114x:~$ #############################################
michel@deb114x:~$ cat t2.txt | cat - t1.txt
t2.txt vers stdin de la commande qui sera après le pipe => sera remplacé par le tiret
contenu de t1.txt
michel@deb114x:~$ 
michel@deb114x:~$ cat t2.txt | cat t1.txt -
contenu de t1.txt
t2.txt vers stdin de la commande qui sera après le pipe => sera remplacé par le tiret
michel@deb114x:~$ 

cat ne concatène rien du tout. Comme l’a écrit @Micp, il affiche le contenu du fichier passé en argument. L’affichage des messages d’erreurs est dû à la sortie d’erreur de rm qui n’est pas redirigée.

J’ajoute que, dans la ligne de commandes suivante :

rm . .. 2>t.txt | cat t.txt

le pipe connecte :

  • le flux stdout de la commande rm
  • au flux stdin de la commande cat

Le pipe ne prends pas en compte le flux stderr de la commande rm

Mais, dans ce contexte ( …impossible de supprimer …) :

  • La commande rm ne retourne rien du tout par son flux stdout => donc la commande pipe n’aura rien à transmettre au flux stdin de la commande cat
  • de plus, pour que la commande cat lise son flux stdin il faudrait qu’on ne lui ait donné aucun nom de fichier, ou bien qu’on lui spécifie de lire aussi son flux stdin en ajoutant un tiret dans la liste des noms de fichiers à concaténer.
1 J'aime

même si je ne comprends pas pourquoi la transmission des flux se passe ainsi , ça explique le résultat observé . Trop de trous dans la raquette pour que je sois capable de suivre le chemin emprunté par les flux de données . Sans le savoir j"ai visé trop haut .

Mais en séparant les flux je vois mieux ce qu’il se passe , transmissions avec pipe non comprises :

mm@Xfce:~$ rm . .. 1>t1.txt 2>t2.txt
mm@Xfce:~$ cat t1.txt
mm@Xfce:~$ cat t2.txt
rm: impossible de supprimer '.': est un dossier
rm: impossible de supprimer '..': est un dossier

Bonjour

Une page web (récemment mise à jour par l’auteur) très bien faite
concernant les redirections et le pipe :
Introduction à la programmation en Bash → #5 Redirections élémentaires


Et c’est même le document en entier qui vaut le coup d’être lu :
iut-rodez.fr : Introduction à la programmation en Bash (Eric Sanchis)
et si besoin, tu trouveras dans ces pages web un lien vers un fichier pdf

Je pense que c’est plutot
rm quelquechose 2> /tmp/glop || cat /tmp/glop
qui efface le qquelkquechose et affiche les erreurs si il y en a eu tout en les conservant dans un fichier.

bon , grâce au cours de l’IUT Rodez j’ai compris ce qu’il se passe et surtout comment fonctionne un « tube » : rien ne vaut un schéma clair qui m’a fait comprendre où se situait mon erreur .

la sortie est effectivement correcte mais comments’appelle cette commande || , que je ne pense pas avoir rencontrée ?

manuel bash:

         commande_1 && commande_2

   commande_2  est  exécutée  si, et seulement si, commande_1 renvoie zéro
   comme état final (succès).

   Une liste OU a la forme

          commande_1 || commande_2

   commande_2 est exécutée si, et seulement si, commande_1 renvoie un état
   final  différent  de  zéro.  L'état renvoyé par des listes ET et OU est
   l'état final de la dernière commande exécutée dans la liste.

À noter que c’est illogique, en C || = «ou», && = «et», pour évaluer
rm quelquechose 2> /tmp/glop || cat /tmp/glop
on peut s’attendre à ce que bash commence par évaluer rm quelquechose 2> /tmp/glop et, en cas de succès donc de retour de code 0, n’évalue pas le second.Pour &&, en cas d’échec, il évaluerait le second… Or bash fait l’inverse…

$ rm glup && echo pouet
rm: impossible de supprimer ‹ glup ›: Aucun fichier ou dossier de ce type
$ rm glup || echo pouet
rm: impossible de supprimer ‹ glup ›: Aucun fichier ou dossier de ce type
pouet
$

En fait il raisonne comme si code de retour =0 —> succès —> valeur VRAI (donc VRAI || xxx = VRAI, évaluation paresseuse, on n’évalue pas xxx), de même code de retour >0 ----> erreur —> FAUX (donc FAUX && xxx = xxx qu’il faut évaluer)

C’est pareil en shell. Dans les deux cas la seconde expression n’est évaluée que si c’est nécessaire compte tenu du résultat de la première. La seule différence, ce sont les valeurs numériques considérées comme « vrai » ou « faux » qui sont inversées en C et en shell (0 = « vrai/succès » en shell et « faux/échec » en C) mais c’est généralement transparent lorsque les valeurs sont des codes de retour ou des conditions.

Non, en cas d’échec donc code != 0. En cas de succès de la première commande il n’y a pas lieu d’exécuter la seconde.
Dans un OU, il suffit qu’un des opérandes soit vrai pour que le résultat soit vrai donc si le premier opérande est vrai on n’a pas besoin d’évaluer l’autre pour connaître le résultat.

Ben oui, cet inversion 0 = Ok, >0 = souci rend cohérent || = ou et && = et mais va à l’encontre de C. Pour être cohérent avec C il aurait fallu inverser || et && dans bash. Mais bon, une fois qu’on sait que VRAI=0 en bash, c’est correct…

Ces choix sont arbitraires dans les deux cas.
Le choix d’une logique positive par le C est intuitif et compréhensible car le langage est assez bas niveau.
Le choix d’une logique inversée par le shell s’impose à partir du moment ou on décide que le code de retour d’une commande vaut 0 en cas de succès et une autre valeur en cas d’échec (ce qui permet d’indiquer la cause de l’échec avec des valeurs différentes).

J’allais dire que c’est surtout celui des processeurs (JNE, JE) mais JE = égalité du résultat à zéro mais aussi branchement si comparaison vraie (il simule une soustraction, donc égalité = 0), hum… C’est arbitraire, c’est vrai finalement