バックグラウンドプロセスの部分的な出力をパイプし、変数に格納します
バックグラウンド:
サーバーがランダムに使用可能なポートで起動されるプロジェクトに取り組んでいます。サーバーは次のコマンドで起動されます。
node server.js
サーバーの準備が整い、使用可能なポートでのサービスを開始すると、サーバーは次の形式でstdoutに完全なサーバーURL(ポート番号を含む)を(他のログとともに)出力します。
Server started! Listening on URL: http://localhost:12927
このサーバープロセスは、手動で強制終了するまで実行を続けます(そして、他のログを出力し続けます)。
実際の問題:
サーバーを起動してその出力をリッスンするスクリプトを書いています。のようなメッセージが表示されたらすぐに、"Server started! Listening on URL: [SERVER_URL]"
これSERVER_URL
を変数に格納し、スクリプトの後半で処理します(たとえば、自動化テストのためにブラウザーを開きます)。
私が試したこと:
Bashの非常に基本的な理解しか持っていないので、次のオプションを試しました(もちろん、SEについて調査した後)。
grep
正規表現での使用について少し調べました。これは、手動で行う場合(つまり、変数に格納せず、echo
コマンドからパイプするだけの場合)に非常にうまく機能します。SERVER_URL=$(node server.js | grep -m 1 -ohP 'Server started! Listening on URL: \K([^\s$]*)')
ただし、この行ではブロックが発生します。おそらく、ノードサーバーが強制終了されるのを待っています。私の要件は明らかです。サーバーの出力からSERVER_URLを、stdoutでそのURLを吐き出すポイントを超えて待たずに入力したいのです。
また、リダイレクトとプロセス置換を少しいじりました。パイプは実際にはソースプロセスが完了するのを待っていることを学びました。リダイレクトを使用して次のことを実行しようとしましたが、機能しません。
SERVER_URL=$(node server.js >&3 | grep -m 1 -ohP 'Server started! Listening on URL: \K([^\s$]*)')
奇妙な「未処理の「エラー」イベント」例外がスローされます(エラー:EPIPEの書き込み)。
どんな助けでも大歓迎です。ありがとう!
回答
はい、で:
var=$(cmd | grep -m1 pattern)
cmd
のstdoutはへのパイプgrep
であり、grep
'sstdoutはシェルへのパイプです。
grep
最初の一致を見つけた後、それを標準出力に出力して終了します。
シェルはgrep
の出力を読み取ります。grep
終了時にファイルの終わりを参照してください。ただし、の場合bash
、シェルもcmd
終了を待機します。
grep
が終了したため、cmd
のstdoutは壊れたパイプになりました。したがって、次にcmd
stdoutに書き込むときは、SIGPIPE信号を受信して停止します。
ここで問題となるのは、cmd
パターンに一致する最初の行まで読んだら、残りの出力をどうするかということです。
興味がない場合は、それcat
を読み取って破棄するバックグラウンドコマンドを実行できます。
{
url=$(grep -m1 -oP 'Server started! Listening on URL: \K\S+')
cat <&0 > /dev/null & # <&0 to work around the fact that bash redirects
# background commands stdin from /dev/null
} < <(node server.js)
それを保持したい場合は、それをいくつかのファイルにリダイレクトしtail -f
、たとえばシェルで使用してURLメッセージを待つことができます。
node server.js > server.log &
{
IFS= read -r pid
url=$(grep -m1 -oP 'Server started! Listening on URL: \K\S+') kill -- "$pid"
} < <(echo "$BASHPID"; exec tail -n +1 -f server.log)
ここでは、メッセージが見つかった後にテールのpidを渡して、他に何も出力しtail
ない場合tail
は発生しない可能性のあるSIGPIPEによって強制終了されるのを待つのではありません。