unix - vers - shell linux




Connexion de l'entrée_and_output entre deux commandes dans shell/bash (6)

Que diriez-vous d'un tuyau nommé?

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

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

# A < foo | tee logfile | B > foo

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

Mon premier problème est comment connecter le stdout de A à stdin de B et le stdout de B au stdin de AIe, quelque chose comme A | B mais un tuyau bidirectionnel. Je pense que je pourrais résoudre cela en utilisant exec pour rediriger mais je ne pouvais pas le faire fonctionner. Les programmes sont interactifs, donc un fichier temporaire ne fonctionnerait pas.

Le deuxième problème est que je voudrais dupliquer chaque direction et rediriger 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 sortir 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 au moins quelque chose qui fonctionne dans bash sur Cygwin.

Grâce à vos réponses, j'ai trouvé 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 est à l'écoute de la connexion aux ports 47001 et 47002 et répercute tout le trafic vers la sortie standard.

Dans la coquille 2, faites:

bash-3.2$ nc localhost 47001

Dans la coquille 3, faites:

bash-3.2$ nc localhost 47002

Maintenant, les lignes entrées dans le shell 2 seront écrites dans le shell 3 et vice versa et le trafic enregistré 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 dans les réponses peuvent être plus fiables.


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

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


J'ai eu ce problème à un moment donné, et j'ai jeté ensemble ce simple programme 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")
}

Je suggère "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

Ensuite, regardez cette session:

$ coproc ./dialog
$ ./dialog  test  < /dev/fd/${COPROC[0]}  > /dev/fd/${COPROC[1]}
Answer to Question test is ...

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

Bien que je n'aime pas vraiment l'aspect passing-command-lines-as-strings de twinpipe (mentionné par JeeBee ( 139495 )), il pourrait s'agir de votre seule option dans cygwin.





pipe