2008-09-26 129 views
10

我有两个(UNIX)程序A和B从stdin/stdout读取和写入。在shell/bash中连接两个命令之间的输入_and_output

我的第一个问题是如何A的标准输出连接到B B相对于A的标准输入标准输出的标准输入,即,像A | B而是一个双向管道。我怀疑我可以通过using exec to redirect来解决这个问题,但我无法完成它的工作。这些程序是交互式的,所以临时文件不起作用。

第二个问题是,我想通过记录程序到stdout复制每个方向和管重复这样我可以看到,程序之间传递(基于文本的线)的流量。如果我可以解决第一个问题,那么在这里,我可能会开球>(...)。

这两个问题似乎是,他们应该有众所周知的解决方案,但我没能找到任何东西。

我宁愿POSIX壳溶液,或至少一些在bash在Cygwin上工作。

感谢您的回答,我提出了以下解决方案。 A/B命令使用nc来侦听两个端口。日志程序使用sed(使用-u进行无缓冲处理)。

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" 

这听取连接到端口47001和47002和回声所有流量到标准输出。

在壳2做:

bash-3.2$ nc localhost 47001 

在壳3做:

bash-3.2$ nc localhost 47002 

现在线在壳2中输入将被写入到壳3并且反之亦然,交通记录到外壳1 ,是这样的:

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

上面已经在Cygwin

测试

更新:上面的脚本几天后停止工作(!)。显然它可能会陷入僵局。答案中的一些建议可能更可靠。

回答

5

你也许可以使用命名管道逃脱:

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

如何命名管道?

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

对于你的第二部分,我相信三通是正确的答案。因此它变成:

# A < foo | tee logfile | B > foo 
4

您可以使用Expect

Expect是一个自动化交互式应用程序的工具,例如telnet,f​​tp,passwd,fsck,rlogin,tip等。

你可以使用下面的代码(从探索采取期待书)为起点 - 它连接PROC1的输出PROC2,反之亦然的输入,为你的要求:

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

这个问题类似于one我以前问过。其他人提出的解决方案是使用命名管道,但我怀疑你没有在cygwin中使用它们。目前我坚持my own (attempt at a) solution,但它需要/dev/fd/0,你可能也没有。

尽管我不太喜欢twinpipe(由JeeBee(139495)提到)的通过命令行作为字符串的方面,但它可能是您在cygwin中的唯一选项。

3

我在这花了很多时间,放弃了它,最后决定使用ksh(Korn shell),它允许这样做。

cmd1 |& cmd2 >&p <&p 

其中|&是(管道)操作者启动一个共同加工和&p是共同加工的文件描述符。

2

我曾经有过这个问题,我把这个简单的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") 
} 
0

我建议 “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 

然后看到这个会话:

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