Ligação de entrada entre _and_output de dois comandos em concha / festa
Pergunta
Eu tenho dois programas (UNIX) A e B que ler e escrever de stdin / stdout.
Meu primeiro problema é como conectar o stdout de à stdin de B e o stdout de B para o stdin de A. Ou seja, algo como A | B, mas um tubo bidireccional. Eu suspeito que eu poderia resolver isso usando exec para redirecionar mas eu não poderia obtê-lo trabalhar. Os programas são interativos para que um arquivo temporário não iria funcionar.
O segundo problema é que eu gostaria de duplicar cada direção e tubo de uma duplicata através de um programa de log para stdout para que eu possa ver o tráfego (-line baseado em texto) que passam entre os programas. Aqui eu posso fugir com tee> (...) se eu posso resolver o primeiro problema.
Ambos estes problemas parece que eles deveriam ter sabido soluções, mas eu não ser capaz de encontrar qualquer coisa.
Eu preferiria uma solução shell POSIX, ou pelo menos algo que funciona em bash em cygwin.
Graças às suas respostas eu vim com a solução seguinte. A / B comanda usos nc para ouvir duas portas. Os usos do programa de registro sed (com u para processamento sem 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"
Este escutas para conexão à porta 47001 e 47002 e ecos todo o tráfego para a saída padrão.
No shell 2 fazer:
bash-3.2$ nc localhost 47001
No shell 3 fazer:
bash-3.2$ nc localhost 47002
Agora linhas inscritas no shell 2 será escrito que desembolsar 3 e vice-versa eo tráfego registrado que desembolsar 1, algo como:
B->A: input to port 47001
A->B: input to port 47002
O texto acima foi testado em Cygwin
Update: O script acima parou de funcionar depois de alguns dias (!). Aparentemente, ele pode impasse. Algumas das sugestões nas respostas podem ser mais confiáveis.
Outras dicas
Como cerca de um pipe nomeado?
# mkfifo foo
# A < foo | B > foo
# rm foo
Para a sua segunda parte acredito tee é a resposta correta. Assim torna-se:
# A < foo | tee logfile | B > foo
Você provavelmente poderia fugir com pipes nomeados:
mkfifo pipe
gawk '$1' < pipe | gawk '$1' > pipe
Você pode usar Esperar .
Esperar é uma ferramenta para a automatização de aplicações interactivas, tais como telnet, ftp, passwd, fsck, Rlogin, ponta, etc.
Você pode usar o código a seguir (retirado do Explorando esperar livro) como um ponto de partida - ele se conecta a saída do proc1 à entrada do proc2 e vice-versa, como você pediu:
#!/usr/bin/expect -f
spawn proc1
set proc1 $spawn_id
spawn proc2
interact -u $proc1
Eu passei muito tempo com isso, deu-se, e por último decidiu usar ksh (o shell Korn), que permite isso.
cmd1 |& cmd2 >&p <&p
onde |&
é um operador (pipe) para iniciar um co-processo e &p
é descritor de que a co-processo de arquivo.
Eu tive esse problema em um ponto, e eu joguei junto este programa C simples.
#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 questão é semelhante ao eu perguntei antes . As soluções propostas por outros estavam a utilizar os pipes nomeados, mas eu suspeito que você não tê-los em cygwin. Atualmente eu estou aderindo a minha própria (tentativa de) solução , mas requer /dev/fd/0
que você provavelmente também não tem.
Embora eu realmente não gosto do passar-Command-linhas-as-cordas aspecto twinpipe
(mencionado por JeeBee ( 139.495 )), pode ser sua única opção no cygwin.
Eu sugiro "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
Então veja esta sessão:
$ coproc ./dialog
$ ./dialog test < /dev/fd/${COPROC[0]} > /dev/fd/${COPROC[1]}
Answer to Question test is ...