15

ツール ala のようなコマンドを実行するために使用したい popen3 を使用すると、予期しない動作が発生しますcmd < file1 > file2。以下の例はハングするため、stdout done到達することはありません。それ以外のツールを使用catすると、ハングアップする可能性があるため、stdin done到達することはありません。バッファリングに苦しんでいると思いますが、これを修正するにはどうすればよいですか?

#!/usr/bin/env ruby

require 'open3'

Open3.popen3("cat") do |stdin, stdout, stderr, wait_thr|
  stdin.puts "foobar"

  puts "stdin done"

  stdout.each_line { |line| puts line }

  puts "stdout done"

  puts wait_thr.value
end

puts "all done"
4

3 に答える 3

15

stdout.each_lineの出力ストリームがまだ開いているcatため、 は からのさらなる出力を待っています。入力ストリームがまだ閉じられていないため、 はまだユーザーからの入力を待っているため、まだ開いています (ターミナルで開いて in と入力すると、 を押すまで実行され、入力を待っていることに気付くcatでしょう)ストリームを閉じます)。catcatfoobar^d

stdin.closeしたがって、これを修正するには、出力を印刷する前に呼び出すだけです。

于 2012-01-21T09:51:15.190 に答える
7

Tilo と sepp2k の答えは正しいです。 を閉じるstdinと、簡単なテストが終了します。問題が解決しました。

sepp2kの回答に対するコメントでは、まだハングが発生していることを示しています。さて、あなたが見落としているかもしれないいくつかのトラップがあります。

stderr のフル バッファでスタックする

無名パイプのバッファーが保持できる量 (現在の Linux では 64KiB) を超える量を stderr に出力するプログラムを呼び出すと、プログラムは中断されます。中断されたプログラムは、stdout を終了したり閉じたりしません。その結果、stdout からの読み取りがハングします。したがって、正しく実行したい場合はIO.select、stdout と stderr の両方から並行して、または行き詰まることなく順番に読み取るために、スレッドまたはノンブロッキングでバッファリングされていない読み取りを使用する必要があります。

stdin のフル バッファでスタックする

プログラムに "foobar" よりも多く (はるかに多く) フィードしようとすると ( cat)、stdout の無名パイプのバッファーがいっぱいになります。OS がサスペンドしcatます。さらに stdin に書き込むと、stdin 用の無名パイプのバッファがいっぱいになります。次に、への呼び出しstdin.writeがスタックします。つまり、標準入力への書き込み、標準出力からの読み取り、標準エラー出力からの読み取りを並行して、または交互に行う必要があります。

結論

良書 (Richards Stevens 著、「UNIX ネットワーク プログラミング: プロセス間通信」) を読み、優れたライブラリ関数を使用してください。IPC (プロセス間通信) は複雑すぎて、実行時の動作が不確定になりがちです。試行錯誤して正しいものにしようとするのは面倒です。

を使用しOpen3.capture3ます。

于 2014-11-01T23:09:30.310 に答える