Question

J'ai deux programmes (UNIX) A et B qui lisent et écrivent à partir de stdin / stdout.

Mon premier problème est de savoir comment connecter la sortie standard de A à la commande standard de B et la sortie standard de B au paramètre standard de A. ie., quelque chose comme A | B mais un tuyau bidirectionnel. Je suppose que je pourrais résoudre cela en en utilisant exec pour rediriger mais je n'ai pas pu l'obtenir travailler. Les programmes sont interactifs et un fichier temporaire ne fonctionnerait pas.

Le deuxième problème est que je voudrais dupliquer chaque direction et diriger un doublon via un programme de journalisation vers stdout afin que je puisse voir le trafic (basé sur la ligne de texte) qui passe entre les programmes. Ici, je peux m'en tirer avec tee > (...) si je peux résoudre le premier problème.

Ces deux problèmes semblent avoir des solutions bien connues, mais je n’ai rien trouvé.

Je préférerais une solution shell POSIX, ou du moins quelque chose qui fonctionne en bash sur cygwin.

Merci à vos réponses, je suis venu avec la solution suivante. Les commandes A / B utilisent nc pour écouter deux ports. Le programme de journalisation utilise sed (avec -u pour le traitement sans tampon).

bash-3.2$ fifodir=$(mktemp -d)
bash-3.2$ mkfifo "$fifodir/echoAtoB"
bash-3.2$ mkfifo "$fifodir/echoBtoA"
bash-3.2$ sed -u 's/^/A->B: /' "$fifodir/echoAtoB" &
bash-3.2$ sed -u 's/^/B->A: /' "$fifodir/echoBtoA" &
bash-3.2$ mkfifo "$fifodir/loopback"
bash-3.2$ nc -l -p 47002 < "$fifodir/loopback" \
          | tee "$fifodir/echoAtoB" \
          | nc -l -p 47001 \
          | tee "$fifodir/echoBtoA" > "$fifodir/loopback"

Ceci écoute la connexion au port 47001 et 47002 et renvoie tout le trafic à la sortie standard.

Dans le shell 2, faites:

bash-3.2$ nc localhost 47001

Dans le shell 3, faites:

bash-3.2$ nc localhost 47002

Maintenant, les lignes entrées dans le shell 2 seront écrites dans le shell 3 et inversement, et le trafic consigné dans le shell 1, quelque chose comme:

B->A: input to port 47001
A->B: input to port 47002

Ce qui précède a été testé sur Cygwin

Mise à jour: le script ci-dessus a cessé de fonctionner après quelques jours (!). Apparemment, cela peut être une impasse. Certaines des suggestions figurant dans les réponses pourraient être plus fiables.

Était-ce utile?

Autres conseils

Qu'en est-il d'un tuyau nommé?

# mkfifo foo
# A < foo | B > foo
# rm foo

Pour votre deuxième partie, je pense que tee est la bonne réponse. Alors ça devient:

# A < foo | tee logfile | B > foo

Vous pourriez probablement vous en sortir avec des pipes nommées:

mkfifo pipe
gawk '$1' < pipe | gawk '$1' > pipe

Vous pouvez utiliser Expect .

  

Expect est un outil permettant d’automatiser des applications interactives telles que telnet, ftp, passwd, fsck, rlogin, tip, etc.

Vous pouvez utiliser le code suivant (tiré du livre Exploring Expect ) comme point de départ: il connecte la sortie de proc1 à l'entrée de proc2 et inversement, comme vous l'avez demandé:

#!/usr/bin/expect -f
spawn proc1
set proc1 $spawn_id
spawn proc2
interact -u $proc1

J'ai passé beaucoup de temps là-dessus, je l'ai abandonné et j'ai finalement décidé d'utiliser ksh (le shell Korn), ce qui permet cela.

cmd1 |& cmd2 >&p <&p

| & amp; est un opérateur (canal) pour démarrer un co-processus et & amp; p est le descripteur de fichier de ce co-processus.

J'ai eu ce problème à un moment donné et j'ai jeté ensemble ce simple programme en C.

#include <stdio.h>
#include <unistd.h>

#define PERROR_AND_DIE(_x_) {perror(_x_); _exit(1);}

int main(int argc, char **argv) {
    int fd0[2];
    int fd1[2];


    if ( argc != 3 ) {
        fprintf(stdout, "Usage %s: \"[command 1]\" \"[command 2]\"\n", argv[0]);
        _exit(1);
    }

    if ( pipe(fd0) || pipe(fd1) ) PERROR_AND_DIE("pipe")

    pid_t id = fork();
    if ( id == -1 ) PERROR_AND_DIE("fork");

    if ( id ) {
        if ( -1 == close(0) )  PERROR_AND_DIE("P1: close 0");
        if ( -1 == dup2(fd0[0], 0) ) PERROR_AND_DIE("P1: dup 0"); //Read my STDIN from this pipe

        if ( -1 == close(1) )  PERROR_AND_DIE("P1: close 1");
        if ( -1 == dup2(fd1[1], 1) ) PERROR_AND_DIE("P1: dup 1"); //Write my STDOUT here
        execl("/bin/sh", "/bin/sh", "-c", argv[1], NULL);
        PERROR_AND_DIE("P1: exec")
    }

    if ( -1 == close(0) )  PERROR_AND_DIE("P2: close 0");
    if ( -1 == dup2(fd1[0], 0) ) PERROR_AND_DIE("P2: dup 0");

    if ( -1 == close(1) )  PERROR_AND_DIE("P2: close 1");
    if ( -1 == dup2(fd0[1], 1) ) PERROR_AND_DIE("P2: dup 1");


    execl("/bin/sh", "/bin/sh", "-c", argv[2], NULL);
    PERROR_AND_DIE("P2: exec")
}

Cette question est similaire à la une que j'ai posée auparavant. . Les solutions proposées par d'autres consistaient à utiliser des canaux nommés, mais je suppose que vous ne les avez pas dans cygwin. Actuellement, je m'en tiens à ma propre solution (tentative de) , mais il nécessite / dev / fd / 0 , ce que vous n'avez probablement pas non plus.

Bien que je n'aime pas vraiment l'aspect "pass-command-lines-as-strings" de twinpipe (mentionné par JeeBee ( 139495 )), cela pourrait être votre seule option dans cygwin.

Je suggèrerais "coproc":

#! /bin/bash
# initiator needs argument

if [ $# -gt 0 ]; then
  a=$1
  echo "Question $a"
else
  read a
fi

if [ $# -gt 0 ]; then
  read a
  echo "$a" >&2
else
  echo "Answer to $a is ..."
fi

exit 0

Puis voir cette session:

$ coproc ./dialog
$ ./dialog  test  < /dev/fd/${COPROC[0]}  > /dev/fd/${COPROC[1]}
Answer to Question test is ...
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top