shell / bashの2つのコマンド間で入力_and_outputを接続する
質問
stdin / stdoutを読み書きする2つの(UNIX)プログラムAとBがあります。
最初の問題は、Aの標準出力をBの標準入力に接続する方法と、Bの標準出力をAの標準入力に接続する方法です。 B、ただし双方向パイプ。 execを使用してリダイレクトすることでこれを解決できると思いますが、取得できませんでした働く。プログラムはインタラクティブなので、一時ファイルは機能しません。
2番目の問題は、各方向を複製し、その複製をロギングプログラムを介してstdoutにパイプして、プログラム間を通過する(テキスト行ベースの)トラフィックを確認できるようにすることです。ここで、最初の問題を解決できれば、ティー>(...)で逃げることができます。
これらの問題はどちらも、よく知られた解決策があるはずですが、何も見つかりません。
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でテスト済みです
更新:上記のスクリプトは数日後に動作を停止しました(!)。どうやらデッドロックする可能性があります。回答のいくつかの提案はより信頼できる場合があります。
他のヒント
名前付きパイプはどうですか?
# mkfifo foo
# A < foo | B > foo
# rm foo
2番目の部分については、teeが正しい答えだと思います。したがって、次のようになります。
# A < foo | tee logfile | B > foo
おそらく名前付きパイプで逃げることができます:
mkfifo pipe
gawk '$1' < pipe | gawk '$1' > pipe
Expect を使用できます。
Expectは、telnet、ftp、passwd、fsck、rlogin、tipなどの対話型アプリケーションを自動化するためのツールです。
開始点として次のコード( Exploring Expect ブックから抜粋)を使用できます-要求に応じて、proc1の出力をproc2の入力に接続します。 p>
#!/usr/bin/expect -f
spawn proc1
set proc1 $spawn_id
spawn proc2
interact -u $proc1
これに多くの時間を費やし、それをあきらめ、最後にこれを可能にするksh(Kornシェル)を使用することにしました。
cmd1 |& cmd2 >&p <&p
|&amp;
はコプロセスを開始する(パイプ)演算子であり、&amp; p
はそのコプロセスのファイル記述子です。
ある時点でこの問題が発生したため、この単純な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")
}
この質問は 1つに似ています。他の人が提案した解決策は名前付きパイプを使用することでしたが、cygwinにはないのではないかと思います。現在、私は自分の(aの試み)ソリューションに固執しています、ただし / dev / fd / 0
が必要ですが、これもおそらく持っていないでしょう。
twinpipe
の文字列としてのコマンド行の渡し方はあまり好きではありませんが(JeeBee( 139495 )))、cygwinでの唯一のオプションかもしれません。
&quot; coproc&quot;をお勧めします:
#! /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 ...