web-dev-qa-db-ja.com

数値ファイル記述子の代わりに名前付きパイプstdoutリダイレクト

だから私は今何時間もいじっていました。私は次の問題を抱えています:

process.stdout.writeを介してstdoutに書き込むコマンド(node.jsスクリプト)を実行しています。これはインタラクティブで、ある時点で終了します。

サブシェルを作成したので終了結果が必要ですが、親でアクティブにする必要があるので、次のように出力を親シェルにリダイレクトします。

exec 4>&1; res=$(exec 3>&1 1>&4; node test.js)

そのコマンドの背後にある考え方は何ですか?1>&4は、ノードtest.jsの出力がメイン(親)シェルに送られることを確認します。 3>&1を使用して、プロセスのRESULTをサブシェルに書き込むことができるように別のパイプを開いて、$resに含めることができるようにします。

例(擬似コード):

//node.js script:
process.stdout.write('write to parent Shell because 1>&4')
writeToPipe('/dev/fd/3', 'write the RESULT to subshell so that we can have it in the $res variable')

今、それの問題は何ですか?

問題は(おそらく私の側のシェル/ UNIXでの誤解による)、単に/dev/fd/3に書き込みたくないということです。なぜなら、他の誰かが/dev/fd/3にも書き込みをしている場合はどうなるでしょうか。これは、単にfd/3を開いてそれを使用するだけの実装としてはあまり良いものではないと思います。誰かが私のプロセスの複数を呼び出し、それらが衝突した場合はどうなりますか?

私がそれを解決しようとした方法

私は次のようなことができると思いました:

tmppipe=$(mktemp -u)
mkfifo "$tmppipe" 

毎回一意の名前付きパイプを生成し、衝突を回避できたからです。

問題は、それが機能しないことです。 「些細な代用」の方法で、私は最初にこれを試していました:

exec 4>&1; res=$(exec "$tmppipe">&1 1>&4; node test.js)

しかし、これは機能しません。名前付きパイプのこの構文では機能しないと思いますが、ターミナルがアクセス許可の問題があることを通知し、終了します。

1
androidavid

パイプとファイル記述子のジャグリングで意図しているのは、test.jsがユーザーと何らかの形で対話することです。

test.jsの標準出力を使用します。ユーザーに質問すると、ユーザーは標準入力に応答します。 test.jsプログラムは何らかの方法で標準出力に最終出力を提供する必要があるため、コマンド置換にデータを提供するには、ファイル記述子3を置換で標準出力に接続し、最終出力を書き込むように編成します。 test.jsのこの記述子に。

これは少し厄介です。

ツールの最終出力の一部ではないインタラクティブなユーザーダイアログ、つまりインタラクティブな質問、診断エラーメッセージ、プログレスバーなどを処理する一般的に受け入れられている方法は、これらを標準エラーストリームに出力することです。これにより、デフォルトで、これらのメッセージはターミナルに直接送信され(ファイル記述子2のリダイレクトが設定されていない場合)、したがって、コマンド置換によってキャプチャされた結果やパイプを介して送信された結果などにはなりません。

これがシェルや他の多くのツールの仕組みです。シェルは標準エラーでプロンプトを出します。 bashシェルはそのselectステートメント出力(一種のメニュー)を標準エラーに書き込み、read -p 'text'コマンドは標準エラーストリームにtextを出力してプロンプトを表示します。ユーザー、および(明らかに)標準エラーでエラーメッセージを出力します。

したがって、コードは次のように簡略化できます。

res=$(node test.js)

ここで、test.jsは、標準エラーストリームでユーザーと対話し、標準入力ストリームでユーザーの入力を読み取り、最後に、変数resに格納する必要がある標準出力ストリームで出力を生成します。シェル。

bashシェルでのこれの短いデモ:

res=$( read -p 'enter something: '; printf 'You entered "%s"\n' "$REPLY" )
printf '"$res" is now "%s"\n' "$res"

resの最終値はnot文字列enter something: を含みます。これは、readユーティリティによって標準エラーストリームに書き込まれたためです。

0
Kusalananda