Pregunta

Tengo dos (UNIX) programas A y B que leen y escriben desde stdin / stdout.

Mi primer problema es cómo conectar el stdout de A al stdin de B y el stdout de B al stdin de A. Es decir, algo como A | B pero una tubería bidireccional. Sospecho que podría resolver esto mediante usando exec para redireccionar pero no pude conseguirlo trabajar. Los programas son interactivos, por lo que un archivo temporal no funcionaría.

El segundo problema es que me gustaría duplicar cada dirección y canalizar un duplicado a través de un programa de registro a la salida estándar para que pueda ver el tráfico (basado en líneas de texto) que pasa entre los programas. Aquí puedo salir con tee > (...) si puedo resolver el primer problema.

Ambos problemas parecen tener soluciones bien conocidas pero no he podido encontrar nada.

Preferiría una solución de shell POSIX, o al menos algo que funcione en bash en cygwin.

Gracias a sus respuestas se me ocurrió la siguiente solución. Los comandos A / B usan nc para escuchar dos puertos. El programa de registro utiliza sed (con -u para el procesamiento sin búfer).

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"

Esto escucha la conexión al puerto 47001 y 47002 y envía todo el tráfico a la salida estándar.

En shell 2 hacer:

bash-3.2$ nc localhost 47001

En shell 3 hacer:

bash-3.2$ nc localhost 47002

Ahora las líneas ingresadas en el shell 2 se escribirán en el shell 3 y viceversa y el tráfico registrado en el shell 1, algo así como:

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

Lo anterior ha sido probado en Cygwin

Actualización: el script anterior dejó de funcionar después de unos días (!). Aparentemente puede llegar a un punto muerto. Algunas de las sugerencias en las respuestas pueden ser más confiables.

¿Fue útil?

Otros consejos

¿Qué tal una tubería con nombre?

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

Para tu segunda parte, creo que la respuesta es la correcta. Así se convierte en:

# A < foo | tee logfile | B > foo

Probablemente podría salirse con la suya con tuberías:

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

Puede usar Expect .

  

Expect es una herramienta para automatizar aplicaciones interactivas como telnet, ftp, passwd, fsck, rlogin, tip, etc.

Puede usar el siguiente código (tomado del libro Exploring Expect ) como punto de partida: conecta la salida de proc1 con la entrada de proc2 y viceversa, como solicitó:

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

Pasé mucho tiempo en esto, lo dejé y decidí usar ksh (el caparazón de Korn), que permite esto.

cmd1 |& cmd2 >&p <&p

donde | & amp; es un operador (pipe) para iniciar un co-proceso y & amp; p es el descriptor de archivo de ese co-proceso.

Tuve este problema en un momento, y creé este sencillo programa 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")
}

Esta pregunta es similar a una que pregunté antes . Las soluciones propuestas por otros eran usar tuberías con nombre, pero sospecho que no las tienes en cygwin. Actualmente me atengo a mi propia (intento de una) solución , pero requiere / dev / fd / 0 que probablemente tampoco tenga.

Aunque realmente no me gusta el aspecto de pasar líneas de comando como cadenas de twinpipe (mencionado por JeeBee ( 139495 )), podría ser su única opción en cygwin.

Sugeriría " 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

Entonces ve esta sesión:

$ coproc ./dialog
$ ./dialog  test  < /dev/fd/${COPROC[0]}  > /dev/fd/${COPROC[1]}
Answer to Question test is ...
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top