Comment diriger la sortie de commande vers d'autres commandes?

83

Exemple:

ls | echon'imprime rien (une ligne vierge, en fait). Je m'attendrais à ce qu'il imprime une liste de fichiers.

ls | grep 'foo'd’autre part, fonctionne comme prévu (imprime les fichiers avec le nom "foo" dans leur nom).

Ce que je fais dans ces situations ressemble à quelque chose comme ls | while read OUT; do echo $OUT; donececi : mais c'est plutôt lourd.

Pourquoi la tuyauterie fonctionne-t-elle avec certaines commandes mais pas avec d'autres? Comment puis-je contourner ce problème?

Mihai Rotaru
la source
2
Que comptez-vous ls | echofaire? pourquoi ne pas simplement courir ls?
theomega
12
J'ai utilisé l'exemple le plus simple qui illustre mon propos. J'ai effectivement rencontré ce problème lorsque j'essayais de créer une ligne qui afficherait les objets git dans le magasin d'objets et leur type. Donc, j'ai transmis les ID d'objet à git cat-file, mais ça n'a pas fonctionné. Apparemment, echo a le même comportement, je l'ai donc utilisé comme exemple.
Mihai Rotaru
Regardez également la commande -n pour xargs, elle indique le nombre d'arguments à placer dans la sous-commande. `... | xargs -n1 git cat-file`
Rich Homolka

Réponses:

118

Il existe une distinction entre les arguments de ligne de commande et les entrées standard. Un tuyau connectera la sortie standard d'un processus à l'entrée standard d'un autre. Alors

ls | echo

Connecte la sortie standard de ls à l’entrée standard d’écho. Bien d'accord? Eh bien, echo ignore l’entrée standard et dumpera ses arguments en ligne de commande - qui ne sont dans ce cas aucunes - sa propre sortie standard. La sortie: rien du tout.

Il y a quelques solutions dans ce cas. La première consiste à utiliser une commande qui lit stdin et effectue un dump sur stdout, tel que cat.

ls | cat

Will 'work', en fonction de votre définition du travail.

Mais qu'en est-il du cas général. Ce que vous voulez vraiment, c'est convertir stdout d'une commande en arguments de ligne de commande d'une autre. Comme d'autres l'ont déjà dit, xargsl'outil d'assistance canonique est dans ce cas, la lecture de sa ligne de commande arguant d'une commande à partir de son stdin et la construction de commandes à exécuter.

ls | xargs echo

Vous pouvez également convertir ceci en utilisant la commande de substitution $()

echo $(ls)

Feriez aussi ce que vous voulez.

Ces deux outils sont assez fondamentaux pour les scripts shell, vous devriez apprendre les deux.

Pour être complet, comme vous l'avez indiqué dans la question, l'autre méthode de base pour convertir stdin en arguments de ligne de commande est la readcommande intégrée du shell . Il convertit les "mots" (les mots définis par la IFSvariable) en une variable temporaire que vous pouvez utiliser dans toutes les commandes.

Rich Homolka
la source
1
Une réponse très utile et informative, merci! J'apprends actuellement bash et j'ai déjà vu à la fois xargs et la notation $ (*), mais je n'y ai pas fait très attention. Maintenant, je sais à quel point ils sont importants et je vais certainement les examiner.
Mihai Rotaru
1
xargs était peut-être ce que cherchait OP.
Iktys
19

ls | echoaffiche seulement une ligne vierge, car echoaucune entrée n’est lue; la dernière commande du pipeline est en fait d’ echoimprimer une ligne vierge.

Généralement:

a | b

fait en sorte que la sortie de adevenir l'entrée de b. Je vous suggère de lire la Pipelinessection de man bash.


Si vous voulez vraiment utiliser lset echoensemble, voici quelques exemples (plutôt inutiles):

ls | xargs -L 1 echo
echo `ls`
for i in `ls` ; do echo $i ; done
cYrus
la source
11

Si vous voulez echola lscommande, essayez:

ls | xargs echo

Cela appellera echoavec la sortie de ls.

Nathan Fellman
la source
3
Ou ls | xargs -I {} echo {}si vous voulez que chaque ligne soit appelée individuellement
Alex Abdugafarov
3

Pourquoi ne pas simplement utiliser:

echo `ls`

Ou beaucoup plus sûr:

echo "`ls -lrt`"
Urbwzrd
la source
4
Ou même juste echo *.
Kazark