Tout le monde sait comment faire tuyau unidirectionnel entre deux programmes (bind stdout
de première et stdin
de seconde): first | second
.
Mais comment faire un tuyau bidirectionnel, c'est-à-dire une liaison croisée stdin
et stdout
de deux programmes? Y a-t-il un moyen facile de le faire dans une coquille?
Eh bien, c’est assez "facile" avec des pipes nommées (
mkfifo
). Je mets easy entre guillemets car, à moins que les programmes ne soient conçus pour cela, un blocage est probable.Maintenant, il y a normalement un tampon impliqué dans l'écriture de stdout. Donc, par exemple, si les deux programmes étaient:
vous vous attendriez à une boucle infinie. Mais au lieu de cela, les deux seraient dans l'impasse; vous auriez besoin d'ajouter
$| = 1
(ou l'équivalent) pour désactiver la mise en mémoire tampon de sortie. Le blocage est dû au fait que les deux programmes attendent quelque chose sur stdin, mais ils ne le voient pas car ils sont dans le tampon stdout de l'autre programme et n'ont pas encore été écrits dans le tuyau.Mise à jour : intégrant les suggestions de Stéphane Charzelas et Joost:
fait la même chose, est plus court et plus portable.
la source
prog1 < fifo | prog2 > fifo
.prog1 < fifo | tee /dev/stderr | prog2 | tee /dev/stderr > fifo
.prog2 < fifo0 > fifo1
, vous pouvez éviter votre petite danse avecexec 30< ...
(qui d'ailleurs ne fonctionne qu'avecbash
ouyash
pour des fds supérieurs à 10 comme ça).dash
semble bien aussi (mais se comporte un peu différemment)Je ne sais pas si c'est ce que vous essayez de faire:
Cela commence par ouvrir un socket d’écoute sur le port 8096 et, une fois la connexion établie, lance le programme en spécifiant
second
sonstdin
comme sortie de flux etstdout
son entrée de flux.Ensuite, une seconde
nc
est lancée qui se connecte au port d’écoute et génère le programmefirst
avec sonstdout
entrée etstdin
la sortie du flux.Ce n'est pas exactement fait en utilisant un tuyau, mais il semble faire ce dont vous avez besoin.
Comme cela utilise le réseau, cela peut être fait sur 2 ordinateurs distants. C'est presque ainsi que fonctionnent un serveur Web (
second
) et un navigateur Web (first
).la source
nc -U
pour les sockets de domaine UNIX qui prennent uniquement un espace d'adressage de système de fichiers.Vous pouvez utiliser pipexec :
la source
bash
la version 4 a unecoproc
commande qui permet de le faire en purbash
sans les pipes nommées:D'autres coquilles peuvent aussi faire
coproc
aussi bien.Vous trouverez ci-dessous une réponse plus détaillée, mais trois chaînes au lieu de deux, ce qui en fait un peu plus intéressant.
Si vous êtes heureux d'utiliser aussi
cat
etstdbuf
puis construire peut être plus facile à comprendre.Version utilisant
bash
aveccat
etstdbuf
, facile à comprendre:Notez que vous devez utiliser eval car le développement de variable dans <& $ var est illégal dans ma version de bash 4.2.25.
Version using pure
bash
: divisez en deux parties, lancez le premier pipeline sous coproc, puis lancez la deuxième partie (une seule commande ou un pipeline) en la reconnectant à la première:Preuve de concept:
fichier
./prog
, juste un programme factice à utiliser, baliser et réimprimer des lignes. Utiliser des sous-réservoirs pour éviter les problèmes de mise en mémoire tampon est peut-être excessif, ce n'est pas le problème.file
./start_cat
Ceci est une version utilisantbash
,cat
etstdbuf
ou fichier
./start_part
. Ceci est une version utilisant purbash
uniquement. Pour les besoins de la démonstration, je l’utilise encorestdbuf
car votre programme réel devra de toute façon gérer la mise en mémoire tampon en interne pour éviter le blocage en raison de la mise en mémoire tampon.Sortie:
Ça le fait.
la source
Un bloc de construction pratique pour l'écriture de tels canaux bidirectionnels est quelque chose qui relie le stdout et le stdin du processus en cours. Appelons-le ioloop. Après avoir appelé cette fonction, il vous suffit de démarrer un tuyau normal:
Si vous ne voulez pas modifier les descripteurs du shell de niveau supérieur, exécutez ceci dans un sous-shell:
Voici une implémentation portable de ioloop utilisant un tube nommé:
Le canal nommé n'existe que brièvement dans le système de fichiers lors de la configuration de ioloop. Cette fonction n'est pas tout à fait POSIX car mktemp est obsolète (et potentiellement vulnérable à une attaque de race).
Une implémentation spécifique à Linux utilisant / proc / est possible et ne nécessite pas de canal nommé, mais je pense que celle-ci est plus que suffisante.
la source
( : <$FIFO & )
plus en détail. Merci d'avoir posté.mktemp
? Je l'utilise beaucoup, et si un outil plus récent a pris sa place, j'aimerais commencer à l'utiliser.Il y a aussi
dpipe
, le "tuyau bidirectionnel", inclus dans le package vde2 et inclus dans les systèmes de gestion des packages distro actuels .dpipe processA = processB
Socat , l'outil de connexion de tout-à-tout.
socat EXEC:Program1 EXEC:Program2
Comme @ StéphaneChazelas a correctement noté dans les commentaires, les exemples ci-dessus sont la "forme de base", il a de bons exemples avec des options sur sa réponse à une question similaire .
la source
socat
utilise des sockets au lieu de tubes (vous pouvez changer cela aveccommtype=pipes
). Vous souhaiterez peut-être ajouter cettenofork
option pour éviter qu'un processus socat supplémentaire ne transfère des données entre les canaux / sockets. (merci pour l'édition sur ma réponse d' ailleurs)Il y a beaucoup de bonnes réponses ici. Donc, je veux juste ajouter quelque chose pour jouer facilement avec eux. Je suppose que
stderr
n'est pas redirigé nulle part. Créez deux scripts (disons a.sh et b.sh):Ensuite, lorsque vous les connecterez, vous devriez voir sur la console:
la source