Est-il possible de rediriger la sortie d'une commande en plusieurs commandes?

21

Pour autant que je sache, je peux utiliser la commande tee pour diviser la sortie standard sur l'écran et d'autres fichiers:

command -option1 -option2 argument | tee file1 file2 file3 

Est-il possible de rediriger la sortie vers des commandes au lieu de fichiers en utilisant tee, afin que je puisse théoriquement créer une chaîne de commandes?

Abdul Al Hazred
la source
3
Expliquez ce que vous entendez par «signal de sortie» et décrivez ce que vous entendez par création d'un «réseau de commandes».
Janis
sous linux, chaque commande a une entrée et deux sorties. ils sont étiquetés avec 0 (pour l'entrée), 1 (pour la sortie) et 2 (pour la sortie d'erreur). Je pensais à 1 quand j'ai dit "signal de sortie" parce que j'ai lu que la commande tee divise uniquement la sortie étiquetée 1. Quand j'ai dit "réseau de commandes" je n'étais pas très technique, je ne sais pas comment le réseau est correctement défini à partir de d'un point de vue mathématique, mais je pensais simplement à un arbre de commandes typologiquement parlant, de sorte que certaines commandes puissent être parents de plus d'une commande enfant.
Abdul Al Hazred
Merci pour la clarification. Veuillez ne pas utiliser le mot signal car il a une signification spécifique dans Unix, et le terme était très trompeur dans ce contexte. Merci encore.
Janis
Sur la ligne de commande, saisissez man -k signal pour découvrir la signification particulière de ce concept clé sous UNIX et Linux. l'homme tuer serait une bonne page pour commencer.
Rob
En outre, de nombreuses personnes qualifient stdin stdout et stderr de «flux» d'entrée ou de sortie. Il y a comme de petites rivières de données donc un ruisseau. Vous aviez raison de chercher un mot pour les décrire collectivement, mais le signal n'est pas le bon mot.
Rob

Réponses:

25

Vous pouvez utiliser des canaux nommés ( http://linux.die.net/man/1/mkfifo ) sur la ligne de commande de teeet faire lire les commandes sur les canaux nommés.

mkfifo /tmp/data0 /tmp/data1 /tmp/data2
cmd0 < /tmp/data0 & cmd1 < /tmp/data1 & cmd2 < /tmp/data2 &
command -option1 -option2 argument | tee /tmp/data0 /tmp/data1 /tmp/data2

Une fois commandterminé, teefermera les canaux nommés, ce qui signalera une EOF (lecture de 0 octet) sur chacun d'eux, ce /tmp/dataNqui mettrait normalement fin aux cmdNprocessus. Exemple réel:

$ mkfifo /tmp/data0 /tmp/data1 /tmp/data2
$ wc -l < /tmp/data0 & wc -w < /tmp/data1 & wc -c < /tmp/data2 &
$ tee /tmp/data0 /tmp/data1 /tmp/data2 < /etc/passwd >/dev/null
$ 61
1974
37

En raison des processus d'arrière-plan, le shell a renvoyé une invite avant la sortie du programme. Les trois instances se sont wcterminées normalement.

Arcege
la source
1
En bash , vous pouvez sécuriser beaucoup de saisie via /tmp/data/{0,1,2}. Là encore, dans bash, vous pouvez utiliser la substitution de processus et ignorer mkfifoentièrement
Tobias Kienzler
2
Pourrait vouloir changer / dev / data0 en / tmp / data0. Merci également d'avoir répondu à la question de manière agnostique. C'est plus utile que de supposer que tout le monde utilise bash.
abonet
15

Si je comprends bien, vous recherchez l'équivalent de tee file1 file2 file3, mais plutôt que d'écrire les mêmes données dans trois fichiers file1, file2et file3, vous voulez diriger les mêmes données dans trois commandes cmd1, cmd2et cmd3, c.-à-d.

… | ??? cmd1 cmd2 cmd3

devrait être équivalent à

… | cmd1 &
… | cmd2 &
… | cmd3 &

sauf que cela ne serait exécuté qu'une seule fois.

Il y a deux façons de procéder.

Ksh93, bash et zsh prennent en charge la substitution de processus . Il s'agit d'une généralisation des canaux qui permet à l'argument d'une commande d'être un fichier qui, lorsqu'il est écrit, transmet des données en entrée à une commande (il existe également la variante d'entrée qui, lorsqu'elle est lue, obtient les données sorties par une commande) . C'est,

echo hello | tee >(cmd1)

imprime hellosur la sortie standard et fonctionne en plus cmd1avec hellocomme entrée.

Ainsi, par exemple, si vous souhaitez dupliquer l'entrée de somecommandet la transmettre aux deux cmd1et cmd2, vous pouvez utiliser

somecommand | tee >(cmd1) | cmd2

Si votre shell ne prend pas en charge la substitution de processus, vous pouvez utiliser des canaux nommés à la place. Voir la réponse d' Arcege pour savoir comment cela fonctionne. Les canaux nommés sont moins pratiques que la substitution de processus car vous devez les créer et les supprimer, puis démarrer et synchroniser les processus manuellement. Ils ont l'avantage d'être entièrement portables, alors que tous les shells ne prennent pas en charge les substitutions de processus. Ils peuvent également être utilisés dans des scénarios autres que ceux pour lesquels la substitution de processus est prévue.

Sous le capot, sur certains systèmes, la substitution de processus utilise des canaux nommés en interne. Sur la plupart des systèmes, cependant, il repose sur des fichiers nommés représentant des descripteurs de fichiers .

Gilles 'SO- arrête d'être méchant'
la source
5
Voir aussi peede moreutils.
Stéphane Chazelas
Notez que la substitution de processus a été introduite par ksh88.
Stéphane Chazelas
6

Au moins dans vous pouvez ignorer la mkfifosubstitution de processus:

command -option1 -option2 argument | tee >(cmd1) >(cmd2) >(cmd3)

ou pour reprendre l'exemple d'Arcege

tee >(wc -l) >(wc -w) >(wc -c) < /etc/passwd >/dev/null
Tobias Kienzler
la source