Comprendre comment les entrées sont envoyées aux tuyaux dans Bash

17

Je ne comprends pas très bien comment fonctionnent les pipes en bash.

Je sais qu'il faut une sortie d'une commande comme entrée dans une autre commande.

Je peux obtenir une sortie car c'est ce que la commande imprime à l'écran.

Mais comment savoir quelle entrée une commande prendra?

Voici un exemple que je pensais fonctionner:

which gem | rm

Malheureusement non.

Quelle gemme s'imprime /usr/bin/gemdonc ça doit être le bon résultat?

Je pensais que cela avait été donné à RM, donc ce serait le cas, rm /usr/bin/gemmais j'avais tort.

Donc ma question est, comment puis-je savoir quelle entrée prend une commande?

ajsie
la source
2
En dehors de toute autre chose, rm /usr/bin/gemc'est une idée terrible . Laissez cela gem(et l'interpréteur Ruby qui va avec) seul et installez votre interprète Ruby préféré (et gem) en utilisant rvm: rvm.beginrescueend.com
Telemachus

Réponses:

23

"Input" et "command line arguments" sont des choses différentes.

rm supprime les fichiers fournis comme arguments.

Un canal redirige la sortie de la commande de gauche vers l'entrée de la commande de droite. Cela n'affecte pas les arguments de ligne de commande du programme de droite.

Pour faire ce que vous essayez de faire, essayez d'utiliser xargspour convertir l'entrée standard en arguments de ligne de commande pour exécuter un programme. Voilà son travail.

which gem | xargs rm, par exemple, supprimera le gemdans votre CHEMIN.

Borealid
la source
12

rmne prend pas d'entrée, il prend des arguments. Ce sont différents. Les arguments sont les commutateurs et les noms de fichiers et ainsi de suite que vous donnez à un programme sur la ligne de commande pour affecter son comportement. L'entrée est les données sur lesquelles le programme travaille. Par exemple, grepprend à la fois l'entrée et les arguments:

grep "foo" file.txt

Il y a deux arguments ici "foo"et file.txt. L' entrée est le contenu de file.txt, pas la chaîne file.txtelle-même. Puisque grep prend des entrées, vous pouvez les utiliser avec des tuyaux:

cat file.txt | grep "foo"

produit la même sortie, car cat prend file.txtcomme argument et produit le contenu de file.txtcomme sortie. Cette sortie est ensuite redirigée vers grep, donnant le même effet que d'avoir grep ouvrir le fichier lui-même, comme dans le premier exemple.

Si vous souhaitez utiliser la sortie d'un programme comme argument d'un autre, vous utilisez des astuces:

rm `which gem`

ou cette syntaxe alternative (spécifique à bash):

rm $(which gem)

Modifier: ou xargscomme le souligne un autre répondeur. De nombreuses façons de dépouiller un chat avec une ligne de commande.

Tyler McHenry
la source
Il convient de noter que cela cat file.txt | grep "foo"peut être des centaines de fois plus lent que grep "foo" file.txt.
Borealid
1
c'est la partie que je ne comprends pas. comment savoir ce qu'est un argument et qu'est-ce qu'une entrée standard?
ajsie
8
@ajsie: Si vous le tapez après le nom du programme et avant d'appuyer sur Entrée, c'est un argument. Si vous le saisissez dans le programme après son démarrage, il s'agit de l'entrée standard.
Borealid
1
Je l'ai! Cela expliquait tout. Maintenant, je sais que je peux utiliser la commande directement et voir si elle m'invite (grep) et je pourrais également lire le manuel (man grep) pour voir si elle utilise l'entrée std.
ajsie
@ajsie: Si vous ne voulez pas plonger dans la page de manuel, il y a aussi grep --helpun aperçu rapide des arguments acceptés.
Borealid
3

Consultez les manpages de commandes qui vous intéressent. Ces programmes indiqueront qu'ils lisent à partir de stdin(essayez man grepune commande populaire qui lit stdin).

dé à coudre
la source
J'ai essayé man grep | grep 'standard input'et obtenu If no file arguments are specified, the standard input is used.comme dernier match. 👍 J'ai dû donner grepun petit avant-goût de sa propre médecine. 😎
ma11hew28
2

Ceux-ci sont tous dangereux à exécuter si vous avez un répertoire dans votre PATH qui contient de l'espace ou si le nom de la commande contient de l'espace:

rm `which gem`       # Dangerous
rm $(which gem)      # Dangerous
which gem | xargs rm # Dangerous

GNU Parallel http: // www.gnu.org/software/parallel/ n'a pas ce problème, donc cela fonctionnera même si vous avez un répertoire dans votre PATH qui contient de l'espace ou si le nom de la commande contient de l'espace:

which gem | parallel rm
parallel -a <(which bass) rm

Regardez la vidéo d'introduction pour GNU Parallel: http://www.youtube.com/watch?v=OpaiGYxkSuQ

Ole Tange
la source