web-dev-qa-db-ja.com

サブプロセスはパイプを開いたままにしますか?

パイプラインで実行されたときにサブプロセスを起動するプログラムの動作を理解しようとしています。

このbashプログラムfork.shは、すぐに出力して返します。

_(sleep 1) &
echo 'here'
_

しかし、パイプに接続すると、読み取り側はスリープが完了するのを待つように見えます。

_$ time bash fork.sh | wc
       1       1       5

real    0m1.014s
_

また、Rubyでこれを試しましたが、スリープがブロックされないようにするための追加の呼び出しがいくつかあります。

_Process.detach(fork { sleep 1 })
puts 'here'
_
_fork {
  sleep 1
  Process.daemon
}
puts 'here'
_

しかし、それらは同じように動作します。

これの原因(Unix、ファイル記述子など)と、パイプラインが1秒以内に戻るようにこれらのいずれかを書き直す方法があるかどうかを知りたいです。


編集:以下の答えは、Rubyの例:daemon()呼び出しを最初に行う必要があることに気付くのに役立ちました。プロセス全体に何らかの形で適用されると思っていました。

1
reentim
  1. 子プロセスは、すべてのファイル記述子を親から継承します。
  2. コマンドを実行するとき(シェルに組み込みがないと仮定した場合のsleepのように)、close-on-execフラグでマークされたファイル記述子のみは閉じていますが、シェルがstdout(fd 1)にそのフラグを設定することはありません。
  3. パイプリーダーは、 all ファイル記述子が書き込み終了を指している場合にのみEOF閉鎖されました。
time bash fork.sh | wc

sleepプロセス(fork.shから開始)は、wcが読み取っているパイプの書き込み終了を指すstdoutをあきらめる必要があります。 fork.sh

(sleep 1 >/dev/null) &
echo 'here'

この場合、sleep .. >&-(stdoutを他の場所にリダイレクトせずに閉じる)も機能する可能性がありますが、プロセスが後でファイルを開くと、返されるファイル記述子は1 =になるため、一般的にはお勧めしません。 stdoutは、仮定を破り、バグを引き起こす可能性があります。

2
mosvy