終了していないプロセスの出力を変数としてキャプチャ

終了していないプロセスの出力を変数としてキャプチャ

この質問は以前に提起され、回答されたと疑われますが、検索が正しいかどうかはわかりません。

起動時にURLとポートを含む行を出力する終了しないプロセス(サーバー)があります。その行を変数としてキャプチャして他のプログラムに渡すことができるようにしたいと思います。

だから私は次のようにします:

% export URL=`server start` &

URLただし、(私の考えでは:-))終了せserverずに実行され続けるため、設定されません。

server他の場所で使用するために印刷されたURLを変数としてキャプチャするにはどうすればよいですか?

答え1

次のことを試すことができます。

server start &
cat /proc/${!}/fd/1

これでサーバーが起動し、$!対応するIDが返されます。 fd/1 は、/proc で使用できるプロセスの標準出力です。

注:異なるプロセスIDを返す可能性があるため、startと$!間に異なるコード行があってはいけません。

答え2

解決策

  1. FIFO(名前付きパイプ)を生成します。他のユーザーから隠す必要がある場合は、事前に一時mktemp -dディレクトリを作成し、その中にFIFOを作成します(この回答では簡潔にするためにこれを行いません)。

    mkfifo myfifo
    
  2. サーバープロセスがFIFOに書き込まれ、FIFOからスクリプトを読み取るようにします。サーバーの起動後に読み取り用にFIFOを開いて閉じる(リーダーがないように)、SIGPIPEはサーバープロセスに送信されるため、先読み用にFIFOを開いて開いたままにすることをお勧めします。一方、FIFOを事前に開くことはホロブロックを読み込み、一部のプロセスが書き込みのために FIFO を開くまで待ちます。この問題を解決するには、読み取りと書き込みのために FIFO を開き、後で記述子を閉じます。

    exec 3<>myfifo
    
  3. バックグラウンドでサーバーを起動し、FIFOに書き込むようにします。

    server start >&3 &
    

    >&3そして>myfifo技術的に異なります。私たちにとって、両方のフォーマットはここで動作します)。

  4. FIFOから正確に1行を読み込みます。

    <&3 IFS= read -r URL
    

    <&3そして<myfifo技術的に異なります。私たちにとって、両方のフォーマットはここで動作します)。

  5. catバックグラウンドで起動し、プロセスがスクリプトの標準出力に印刷されるようにします(または出力を別のものにcatリダイレクトするか、/dev/null必要に応じて調整します)。serverこの手順を省略すると、FIFO に印刷量が多すぎるとブロックが発生します。catこれは、実行したジョブの後にプロセスが何も印刷しないという確信がある場合にのみ必要です。readそのような場合でも、cat何の害もありません。

    一般的に別の問題があります。server読み取り用に開いているすべての記述子を閉じた後、SIGPIPEを使用して終了できます。私たちはserver書くための記述子を自分で持っています。そして読んでSIGPIPEは発生しません。これが発生した場合は、catFIFOから読み取りを開始すると問題が解決します。

    それから始めてくださいcat

    <myfifo cat 3>&- &
    

    myfifoここでは、読み取りのみを有効にしてcat書き込みを許可する記述子を継承することはできません。重要なことは、cat書き込みのためにFIFOを開いたままにしてはいけません。これは後で重要になります。

  6. ディスクリプタを閉じてFIFOのみを開いたままにcatします。serverFIFOの接続を解除することもできます(これにより、FIFOを使用するプロセスは中断されません)。

    exec 3>&-
    rm myfifo
    

    これにより、スクリプトの将来の子孫はその記述子を継承しません。

  7. 仕事$URL

  8. 終了すると、他serverのプロセスは書き込み用にFIFOを開かず、catEOF条件に遭遇して終了します。この時、私たちが始める方法がcat重要です。継承されたファイル記述子が保持されると、正式にcatFIFOの作成者になるため、自動的に終了することはできません。ログアウトcat後は自動的にログアウトすることを保証しますserver

    スクリプトが終わったら、おそらくwait次のことが起こりたいと思います。

    wait
    

    (これは他のバックグラウンドジョブがないと仮定します。)これがないと、スクリプトは以前にwait終了してserverバックグラウンドにserver残ることがあります。catスクリプトが必要かどうかを決定しますwait


概念の証拠

#!/bin/sh

# fake server
server() {
   echo 'example.com'
   for i in 1 2 3 4 5 6 7; do echo 'server running'; sleep 1; done
}

mkfifo myfifo
exec 3<>myfifo

server start >&3 &
<&3 IFS= read -r URL
<myfifo cat 3>&- &

exec 3>&-
rm myfifo

echo "The URL is $URL"
sleep 2
echo "Still working with $URL"
sleep 2
echo "Done. Waiting for the server to close."
wait

関連情報