Rubyにおけるプロセス置換(コマンド置換ではない)
概要
bash、zsh、ksh88、ksh93 および同様のシェルでは、指定されたコード部分が含まれるファイル名 (プラットフォームに応じて /dev/fd エントリまたは名前付きパイプとして実装される) を簡単に生成できます。サブシェルで実行されます。
同じことをRubyインタプリタで行うことに興味があります。引数の1つであるファイル名を使用してサブプロセスを実行し、読み取られると、現在のRubyインタプリタまたはそのサブプロセスで実行されるコードの出力をストリーミングします。
コンテンツはセキュリティに敏感であるため、一時ファイルへの書き込みは理想的ではありません。
bash の同等のコード:
./run-program --password-file=<(printf '%s' "$password")
…実行すると、(Linux または /dev/fd/ を備えた別のプラットフォーム上で) 次のようなものが呼び出されます。
./run-program --password-file=/dev/fd/5
…ここで、 /dev/fd/5 を (ストリームなので 1 回だけ) 読み取って、 を展開した結果を取得できます。
Ruby で同じ呼び出し規約を実装するための最良のアプローチは何ですか?
解決策
IO.popen は、シェルの >() または <() と同じことを行います。つまり、読み書きできる名前のない一方向のパイプを作成します。
fd=IO.popen("echo hi") #"r"--reading by default
fd.read
#=>"hi\n"
#Read from the file object
#OR access via the filesystem representation of the filedescriptor
File.read("/dev/fd/#{fd.fileno}")
#This is just how linux works (note in Linux, each process sees `/dev/fd/` differently--it's actually the open filedescriptors a process has)
基本的に、これには名前のないパイプを使用するとよいでしょう。もう 1 つの一般的なパターンは、IO.pipe でパイプ ペアを作成し、子プロセスをフォークオフすることです。フォークするとファイル記述子が共有されるため、子プロセスと親プロセスは基本的にそのパイプ ペアを介して接続され、そのパイプ ペアは必要なだけ持つことができます。