Comment joindre deux canaux nommés en un seul flux d'entrée sous Linux

64

En utilisant la fonctionnalité pipes ( |) sous Linux, je peux transférer en chaîne l’entrée standard vers un ou plusieurs flux de sortie.

Je peux utiliser teepour diviser la sortie pour séparer les sous-processus.

Existe-t-il une commande pour joindre deux flux d'entrée?

Comment pourrais-je m'y prendre? Comment fonctionne le diff?

Cristian Ciupitu
la source

Réponses:

105

Personnellement, mon préféré (nécessite bash et d’autres fonctions standard sur la plupart des distributions Linux)

Les détails peuvent beaucoup dépendre de ce que les deux choses génèrent et comment vous voulez les fusionner ...

Contenu de commande1 et commande2 l'un après l'autre dans la sortie:

cat <(command1) <(command2) > outputfile

Ou si les deux commandes génèrent des versions alternatives des mêmes données que celles que vous voulez voir côte à côte (je l'ai utilisé avec snmpwalk; les chiffres d'un côté et les noms de MIB de l'autre):

paste <(command1) <(command2) > outputfile

Ou si vous souhaitez comparer le résultat de deux commandes similaires (par exemple, une recherche sur deux répertoires différents)

diff <(command1) <(command2) > outputfile

Ou si elles sont ordonnées des sorties, les fusionner:

sort -m <(command1) <(command2) > outputfile

Ou exécutez les deux commandes à la fois (vous pourriez toutefois brouiller un peu les choses):

cat <(command1 & command2) > outputfile

L'opérateur <() configure un canal nommé (ou / dev / fd) pour chaque commande, en canalisant la sortie de cette commande dans le canal nommé (ou la référence de fichier / dev / fd) et passe le nom sur la ligne de commande. Il y a un équivalent avec> (). Vous pouvez faire: command0 | tee >(command1) >(command2) >(command3) | command4envoyer simultanément le résultat d’une commande à 4 autres commandes, par exemple.

freiheit
la source
impressionnant! J'ai lu la page de manuel de bash depuis longtemps, mais je n'avais pas choisi celle-ci
Javier
2
Vous pouvez trouver la référence dans le [guide de rédaction de bash avancé] ( tldp.org/LDP/abs/html/process-sub.html ) du projet de documentation de Linux
brice le
3
je suis en mesure d'empêcher les lignes intercalées par la tuyauterie à travers grep --line-buffered- pratique pour en même temps que grep« l'ing tailde plusieurs fichiers journaux. voir stackoverflow.com/questions/10443704/line-buffered-cat
RubyTuesdayDONO
16

Vous pouvez ajouter deux vapeurs à une autre avec cat, comme le montre le gorille.

Vous pouvez également créer une FIFO, y diriger la sortie des commandes, puis lire à partir de la FIFO avec n’importe quel autre programme:

mkfifo ~/my_fifo
command1 > ~/my_fifo &
command2 > ~/my_fifo &
command3 < ~/my_fifo

Particulièrement utile pour les programmes qui n'écriront ou liront qu'un fichier, ou pour mélanger des programmes qui ne sortiront que stdout / file avec un qui ne supporte que l'autre.

Chris S
la source
2
Celui-ci fonctionne sur pfSense (FreeBSD) alors que la réponse acceptée ne fonctionne pas. Je vous remercie!
Nathan
9
(tail -f /tmp/p1 & tail -f /tmp/p2 ) | cat > /tmp/output

/tmp/p1et /tmp/p2sont vos canaux d’entrée, tandis que /tmp/outputest la sortie.

gorille
la source
6
Remarque: à moins que les deux commandes situées à l'intérieur du ()flush affichent leur sortie sur chaque ligne (et quelques autres règles POSIX obscures pour l'atomicité), vous pourriez vous retrouver avec une confusion étrange sur l'entrée du chat ...
freiheit
Ne devriez-vous pas utiliser le point-virgule au lieu du caractère esperluette?
Samir
Ce sont des choses épiques
Mobigital
5

J'ai créé un programme spécial pour cela: fdlinecombine

Il lit plusieurs canaux (généralement des sorties de programme) et les écrit sur stdout ligne par ligne (vous pouvez également remplacer le séparateur)

Vi.
la source
Fonctionne comme annoncé. Merci de le rendre public.
alexei
3

Une commande vraiment intéressante que j'ai utilisée pour cela est que tpipevous devrez peut-être compiler car ce n'est pas si courant. C'est vraiment génial de faire exactement ce dont vous parlez, et c'est tellement propre que je l'installe habituellement. La page de manuel se trouve ici http://linux.die.net/man/1/tpipe . Le téléchargement actuellement répertorié se trouve dans cette archive http://www.eurogaran.com/downloads/tpipe/ .

C'est utilisé comme ça,

## Reinject sub-pipeline stdout into standard output:
$ pipeline1 | tpipe "pipeline2" | pipeline3
JM Becker
la source
3

Sois prudent ici; il suffit de les manipuler pour mélanger les résultats d'une manière que vous ne voudrez peut-être pas: par exemple, s'il s'agit de fichiers journaux, vous ne voudrez probablement pas vraiment une ligne insérée à mi-chemin d'une ligne à l'autre. Si ça va, alors

tail -f / tmp / p1 / tmp / p2> / tmp / output

marchera. Si cela ne vous convient pas , vous devrez trouver quelque chose qui mettra en mémoire tampon les lignes et ne produira que des lignes complètes. Syslog fait cela, mais je ne sais pas quoi d'autre pourrait.

EDIT: optimisation pour la lecture sans tampon et les tubes nommés:

Considérant / tmp / p1, / ​​tmp / p2, / tmp / p3 comme des tubes nommés, créés par "mkfifo / tmp / p N "

queue -q -f / tmp / p1 / tmp / p2 | awk '{print $ 0> "/ tmp / p3"; close ("/ tmp / p3"); fflush ();} '&

maintenant par cette voie, nous pouvons lire la sortie nommée pipe "/ tmp / p3" non tamponnée par:

tail -f / tmp / p3

il y a un petit bug de tri, vous devez "initialiser" le 1er pipe d'entrée / tmp / p1 par:

echo -n> / tmp / p1

afin de queue acceptera l'entrée de 2nd pipe / tmp / p2 en premier et n'attendra pas que quelque chose arrive à / tmp / p1. Ce n'est peut-être pas le cas. Si vous êtes sûr, le fichier / tmp / p1 recevra une entrée en premier.

Aussi l'option -q est nécessaire pour la queue n'imprime pas des ordures sur les noms de fichiers.

pjz
la source
le plus utile sera: "tail -q -f / tmp / p1 / tmp / p2 | another_command" car cela se fera ligne par ligne et avec l'option -q, il n'imprimera aucun autre déchet
readyblue
utilisation du fichier / tampon nommé sans tampon : à tail -q -f /tmp/p1 /tmp/p2 | awk '{print $0 > "/tmp/p3"; close("/tmp/p3"); fflush();}' & présent, le fichier / tmp / p3 peut même être nommé tuyau et vous pouvez le lire simplement par tout tail -f /tmp/p3ceci est UNBUFFERED = ligne par ligne, il existe cependant un petit bogue de tri. le 1er fichier / canal nommé doit être initialisé en premier pour que la sortie du 2ème puisse être acceptée. donc vous aurez besoin de echo -n > /tmp/p1et que tout fonctionnera sans heurts.
readyblue
1

Le meilleur programme pour le faire est lmerge. Contrairement à la réponse de Freihart, elle est orientée ligne afin que les sorties des deux commandes ne s'embrouillent pas. Contrairement à d’autres solutions, elle fusionne assez l’entrée afin qu’aucune commande ne puisse dominer la sortie. Par exemple:

$ lmerge <(yes foo) <(yes bar) | head -n 4

Donne la sortie de:

foo
bar
foo
bar
Rian Hunter
la source