サーバー標準出力を読み取り、メッセージ出力後にのみ続行する方法

サーバー標準出力を読み取り、メッセージ出力後にのみ続行する方法

たとえば、単純なNode.jsサーバーがあるとします。

const http = require('http');

const server = http.createServer((req,res) => res.end('foobar'))

server.listen(3000, () => {
   console.log(JSON.stringify({"listening": 3000}));
});

次に、bashを使用します。

#!/usr/bin/env bash

node server.js | while read line; do
  if [[ "$line" == '{"listening":3000}' ]]; then
      :
  fi
done

# here I want to process more crap

私の目標は、サーバーが実際に要求の受信を開始した後にのみスクリプトを実行し続けることです。私が考えることができる最高の点は次のとおりです。

#!/usr/bin/env bash

mkfifo foo
mkfifo bar

(node server.js &> foo) &

(
while true; do
  cat foo | while read line; do
     if [[ "$line" != '{"listening":3000}' ]]; then
       echo "$line"
       continue;
    fi
    echo "ready" > bar
  done
done
) &

cat bar && {
  # do my thing here?
}

これを行うよりクリーンで簡単な方法はありますか?サーバーの準備ができたら続けたいです。私が知っている唯一の良い方法は、stdoutを使用してメッセージを印刷してそのメッセージを受信することです。

答え1

ヘビー級のアプローチは、以下を使用することです。

#!/usr/bin/env expect

spawn node server.js

set timeout -1
expect {{"listening":3000}}

# now you can process all the crap, but in Expect

interact

Bashでは、Bashはfooファイルを処理する必要はありません。どうですか?

#!/usr/bin/env bash

node server.js &> server.out &

# busy wait
while true; do
    grep -q '{"listening":3000}' server.out && break
    sleep 1
done

# continue crap processing

サーバーの使用中にサーバーをデーモン化できます。

node server.js </dev/null &> server.out &
disown $!

答え2

expectGlennの答えは良い一般的な解決策のようです。

より簡単な方法が必要な場合、期待が望まない、またはインストールできない場合は、bashのより小さいバージョンがあります。

#!/usr/bin/env bash

process() {
    # do your stuff
    echo ok
}

node server.js | ( grep -L '{"listening":3000}' ; process ) &

私はgrepの-Lオプション(-lもうまく機能しますが、出力を生成します)を利用して一致を見つけるとすぐに返します。その後、制御は処理機能に渡され、必要に応じて出力を読み続けることもできます。

waitサーバーがシャットダウンする前にスクリプトが返されないようにするには、最後にそれを追加します。

関連情報