たとえば、単純な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
expect
Glennの答えは良い一般的な解決策のようです。
より簡単な方法が必要な場合、期待が望まない、またはインストールできない場合は、bashのより小さいバージョンがあります。
#!/usr/bin/env bash
process() {
# do your stuff
echo ok
}
node server.js | ( grep -L '{"listening":3000}' ; process ) &
私はgrepの-Lオプション(-lもうまく機能しますが、出力を生成します)を利用して一致を見つけるとすぐに返します。その後、制御は処理機能に渡され、必要に応じて出力を読み続けることもできます。
wait
サーバーがシャットダウンする前にスクリプトが返されないようにするには、最後にそれを追加します。