假设我有一个简单的 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
在我看来,格伦的回答是一个很好的通用解决方案。
如果你想要一个更简单的方法,或者不想/无法安装expect,这里有一个bash中的较小版本:
#!/usr/bin/env bash
process() {
# do your stuff
echo ok
}
node server.js | ( grep -L '{"listening":3000}' ; process ) &
我正在利用 grep 的 -L 选项(-l 也可以正常工作,但会产生输出),使其在找到匹配项后立即返回。然后,控制权交给处理函数,如果您愿意,您甚至可以继续读取输出。
wait
如果您不希望脚本在服务器关闭之前返回,请在末尾添加。