web-dev-qa-db-ja.com

シェル:2つのコマンドのSTDIN / STDOUTの相互配管

これをPOSIXシェルで実行すると、

$ cmd0 | cmd1

Cmd0のSTDOUTは、cmd1のSTDINにパイプされます。

Q:これに加えて、どうすればまた cmd1のSTDOUTをcmd0のSTDINにパイプできますか?

名前付きパイプ(FIFO)との間のリダイレクトを使用することは必須ですか?名前付きパイプはいくつかのファイルシステムパスを占有し、名前の衝突について心配する必要があるため、私はあまり好きではありません。または、C、Python、またはいくつかの汎用プログラミング言語を介してpipe(2)を呼び出す必要がありますか?

(cmd0とcmd1はどちらもネットワークI/Oを実行するため、相互に永久にブロックされることはありません。)

3
nodakai

双方向パイプ(Linuxではない)を備えたシステムでは、次のことができます。

cmd0 <&1 | cmd1 >&0

Linuxでは、次のことができます。

{ cmd0 < /dev/fd/3 | cmd1 3>&-; } 3>&1 | :

Linux(およびLinuxのみ)では/dev/fd/xここで、xは名前付きパイプのfdであり、名前付きパイプのように機能します。つまり、読み取りモードで開くと読み取り終了になり、書き込みモードで開くと書き込み終了になります。

yash Shell とそのx>>|yパイプラインリダイレクト演算子

{ cmd0 <&4 3<&- 4<&- | cmd1 >&3 3>&- 4>&-; } 3>>|4

coprocをサポートするシェル

  • zsh:

     coproc cmd0
     cmd1 <&p >&p
    
  • ksh

     cmd0 |&
     cmd1 <&p >&p
    
  • bash4 +

     coproc cmd0
     cmd1 <&"${COPROC[0]}" >&"${COPROC[1]}"
    

専用ツールアプローチ( この非常によく似た質問 の回答から恥知らずにコピー):

pipexec を使用する

pipexec [ A /path/to/cmd0 ] \
        [ B /path/to/cmd1 ] \
        '{A:1>B:0}' '{A:0>B:1}'

または dpipe を使用する

dpipe cmd0 = cmd1

または socat を使用します:

socat EXEC:cmd0 EXEC:cmd1,nofork                 # using socketpairs
socat EXEC:cmd0,commtype=pipes EXEC:cmd1,nofork  # using pipes

pythonについてはわかりませんが、Perlでも比較的簡単に実行できます。

Perl -e 'pipe STDOUT,STDIN; exec "cmd0 | cmd1"'

いずれにせよ、デッドロックに注意してください!

14