Domanda

Ho due programmi (UNIX) A e B che leggono e scrivono da stdin / stdout.

Il mio primo problema è come collegare lo stdout di A allo stdin di B e lo stdout di B allo stdin di A. Cioè, qualcosa come A | B ma un tubo bidirezionale. Sospetto di poterlo risolvere usando exec per reindirizzare ma non sono riuscito a ottenerlo lavorare. I programmi sono interattivi, quindi un file temporaneo non funzionerebbe.

Il secondo problema è che vorrei duplicare ogni direzione e reindirizzare un duplicato tramite un programma di registrazione a stdout in modo da poter vedere il traffico (basato su una riga di testo) che passa tra i programmi. Qui potrei cavarmela con tee > (...) se posso risolvere il primo problema.

Entrambi questi problemi sembrano avere soluzioni ben note ma non sono riuscito a trovare nulla.

Preferirei una soluzione shell POSIX, o almeno qualcosa che funzioni bash su cygwin.

Grazie alle tue risposte ho trovato la seguente soluzione. I comandi A / B usano nc per ascoltare due porte. Il programma di registrazione utilizza sed (con -u per l'elaborazione senza buffer).

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"

Ascolta la connessione alla porta 47001 e 47002 ed echo tutto il traffico verso l'output standard.

Nella shell 2 fare:

bash-3.2$ nc localhost 47001

Nella shell 3 fare:

bash-3.2$ nc localhost 47002

Ora le righe immesse nella shell 2 verranno scritte nella shell 3 e viceversa e il traffico registrato nella shell 1, qualcosa del tipo:

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

Quanto sopra è stato testato su Cygwin

Aggiornamento: lo script sopra ha smesso di funzionare dopo alcuni giorni (!). Apparentemente può deadlock. Alcuni dei suggerimenti nelle risposte potrebbero essere più affidabili.

È stato utile?

Altri suggerimenti

Che ne dici di una pipe con nome?

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

Per la tua seconda parte credo che tee sia la risposta corretta. Quindi diventa:

# A < foo | tee logfile | B > foo

Probabilmente potresti cavartela con le named pipe:

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

Puoi utilizzare Expect .

  

Expect è uno strumento per l'automazione di applicazioni interattive come telnet, ftp, passwd, fsck, rlogin, tip, ecc.

Potresti usare il seguente codice (tratto dal libro Exploring Expect ) come punto di partenza - collega l'output di proc1 all'input di proc2 e viceversa, come richiesto:

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

Ho trascorso molto tempo su questo, ho rinunciato e alla fine ho deciso di usare ksh (la shell Korn), che lo consente.

cmd1 |& cmd2 >&p <&p

dove | & amp; è un operatore (pipe) per avviare un co-processo e & amp; p è il descrittore di file di quel co-processo.

Ho avuto questo problema ad un certo punto e ho messo insieme questo semplice programma 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")
}

Questa domanda è simile a one che ho chiesto prima . Le soluzioni proposte da altri erano di usare pipe denominate, ma sospetto che tu non le abbia in Cygwin. Al momento mi attengo alla la mia (prova a) soluzione , ma richiede / dev / fd / 0 che probabilmente non hai.

Anche se non mi piace molto l'aspetto delle righe di comando di passaggio di twinpipe (menzionato da JeeBee ( 139495 )), potrebbe essere la tua unica opzione in cygwin.

Suggerirei " 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

Quindi vedi questa sessione:

$ coproc ./dialog
$ ./dialog  test  < /dev/fd/${COPROC[0]}  > /dev/fd/${COPROC[1]}
Answer to Question test is ...
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top