如何读取服务器标准输出并仅在输出消息后继续

如何读取服务器标准输出并仅在输出消息后继续

假设我有一个简单的 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如果您不希望脚本在服务器关闭之前返回,请在末尾添加。

相关内容