11

stdin / stdoutから読み取りと書き込みを行う2つの(UNIX)プログラムAとBがあります。

私の最初の問題は、AのstdoutをBのstdinに接続し、BのstdoutをAIeのstdinに接続する方法です。Bしかし双方向パイプ。execを使用してリダイレクトすることでこれを解決できると思いますが、機能させることができませんでした。プログラムはインタラクティブであるため、一時ファイルは機能しません。

2番目の問題は、各方向を複製し、ロギングプログラムを介して複製をstdoutにパイプして、プログラム間を通過する(テキスト行ベースの)トラフィックを確認できるようにすることです。ここで、最初の問題を解決できれば、tee>(...)で逃げることができます。

これらの問題はどちらもよく知られている解決策があるはずですが、私は何も見つけることができませんでした。

私はPOSIXシェルソリューション、または少なくともcygwinのbashで機能するものを好みます。

あなたの答えのおかげで、私は次の解決策を思いつきました。A / Bコマンドは、ncを使用して2つのポートをリッスンします。ロギングプログラムは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でテストされています

更新:上記のスクリプトは数日後に動作を停止しました(!)。どうやらそれはデッドロックする可能性があります。回答の提案のいくつかは、より信頼できるかもしれません。

4

8 に答える 8

10

名前付きパイプはどうですか?

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

あなたの第二の部分については、ティーが正解だと思います。したがって、次のようになります。

# A < foo | tee logfile | B > foo
于 2008-09-26T13:33:35.250 に答える
5

http://bisqwit.iki.fi/source/twinpipe.html

于 2008-09-26T13:26:25.457 に答える
5

あなたはおそらく名前付きパイプで逃げることができます:

mkfifo pipe
gawk '$1' < pipe | gawk '$1' > pipe
于 2008-09-26T13:30:45.383 に答える
4

Expectを使用できます。

Expect は、telnet、ftp、passwd、fsck、rlogin、tip などの対話型アプリケーションを自動化するためのツールです。

次のコード ( Exploring Expectブックから抜粋) を出発点として使用できます。要求どおりに、proc1 の出力を proc2 の入力に、またはその逆に接続します。

#!/usr/bin/expect -f
spawn proc1
set proc1 $spawn_id
spawn proc2
interact -u $proc1
于 2008-09-26T13:49:26.243 に答える
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")
}
于 2011-10-27T03:41:49.063 に答える
1

この質問は、私が以前に尋ねた質問と似ています。他の人が提案した解決策は名前付きパイプを使用することでしたが、cygwin にはそれらがないのではないかと思います。現在、私は自分自身の(試行中の)解決策に固執していますが、それには/dev/fd/0おそらくあなたが持っていないものも必要です。

twinpipe(JeeBee ( 139495 ) が言及) の pass -command-lines-as-strings の側面はあまり好きではありませんが、それが cygwin の唯一のオプションかもしれません。

于 2008-09-26T13:53:29.493 に答える
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 ...
于 2012-11-29T13:09:50.913 に答える