文本匹配后将管道进程延迟到后台

时间:2013-10-23 22:48:42

标签: linux bash shell pipe

所以我有一个bash命令来启动一个服务器,它输出一些行,然后输出“服务器启动,按Control + C退出”之类的东西。我如何管道这个输出,所以当这一行出现时我把这个过程放在后台并继续使用另一个脚本/函数(即做一些需要等到服务器启动的东西,比如运行测试)

我想最终得到3个功能

  • START_SERVER
  • run_tests
  • STOP_SERVER

我有以下几点:

function read_server_output{
    while read data; do
        printf "$data"
        if [[ $data == "Server started, Press Control+C to exit" ]]; then
            # do something here to put server process in the background
            # so I can run another function
        fi
    done
}

function start_server{
    # start the server and pipe its output to another function to check its running
    start-server-command | read_server_output
}

function run_test{
    # do some stuff
}

function stop_server{
    # stop the server
}

# run the bash script code
start_server()
run_tests()
stop_tests()

相关问题可能是SH/BASH - Scan a log file until some text occurs, then exit. How?

先谢谢,我对此很陌生。

2 个答案:

答案 0 :(得分:4)

首先,关于术语的说明......

“背景”和“前景”是控制终端的概念,即它们与键入 ctrl + C ctrl + Z 时发生的情况有关,等等(进程获取信号),进程是否可以从终端设备读取(“后台”进程获得默认导致它停止的SIGTTIN),等等。

很明显,这与你想要达到的目标没什么关系。相反,你有一个不正常的程序(或程序套件),需要一些特殊的溺爱:当服务器首次启动时,它需要一些手持,直到某些点,之后它没关系。一旦输出一些文本字符串,手持可以停止(请参阅相关问题或下面的技术)。

这里存在一个很大的潜在问题:许多程序,当它们的输出被重定向到管道或文件时,产生 no 输出,直到它们打印出一个“块”值的输出,或者是退出。如果是这种情况,那就简单了:

start-server-command | cat

不会打印您正在寻找的行(这样就可以快速判断您是否还必须解决此问题)。如果是这样,你需要像expect这样的东西,这是实现你想要的完全不同的方式。

假设这不是问题,那么让我们尝试一种完全在壳的方法。

你需要的是运行start-server-command并保存进程ID,这样你就可以(最终)发送一个SIGINT信号(如 ctrl + C 那样如果进程 “在前台”,但你是从脚本而不是从控制终端执行此操作,那么脚本无法按下键。幸运的是,sh只有一个语法。

首先让我们制作一个临时文件:

#! /bin/sh
# myscript - script to run server, check for startup, then run tests

TMPFILE=$(mktemp -t myscript) || exit 1    # create /tmp/myscript.<unique>
trap "rm -f $TMPFILE" 0 1 2 3 15           # arrange to clean up when done

现在启动服务器并保存其PID:

start-server-command > $TMPFILE &          # start server, save output in file
SERVER_PID=$!                              # and save its PID so we can end it

trap "kill -INT $SERVER_PID; rm -f $TMPFILE" 0 1 2 3 15 # adjust cleanup

现在,您需要扫描$TMPFILE,直到出现所需的输出,就像在另一个问题中一样。因为这需要一定量的轮询,所以应该插入一个延迟。检查服务器是否发生故障并终止而没有进入“已启动”点也是明智之举。

while ! grep '^Server started, Press Control+C to exit$' >/dev/null; do
    # message has not yet appeared, is server still starting?
    if kill -0 $SERVER_PID 2>/dev/null; then
        # server is running; let's wait a bit and try grepping again
        sleep 1 # or other delay interval
    else
        echo "ERROR: server terminated without starting properly" 1>&2
        exit 1
    fi
done

(此处kill -0用于测试进程是否仍然存在;如果没有,则表示已退出。“cleanup”kill -INT将产生错误消息,但这可能没问题。如果没有,重定向kill命令的错误输出,或者调整清理或手动执行,如下所示。)

此时,服务器正在运行,您可以进行测试。如果您希望它退出,就像用户点击 ctrl + C 一样,请使用SIGINT发送kill -INT

由于kill -INT集合中的trap用于脚本退出(0)以及由SIGHUP(1)终止时SIGINT(2) ),SIGQUIT(3)和SIGTERM(15) - 这就是:

trap "do some stuff" 0 1 2 3 15

部分 - 你可以简单地让你的脚本退出,除非你想特别等待服务器退出。如果你想要,或许:

kill -INT $SERVER_PID; rm -f $TMPFILE   # do the pre-arranged cleanup now
trap - 0 1 2 3 15                       # don't need it arranged anymore
wait $SERVER_PID                        # wait for server to finish exit

是合适的。

(显然以上都没有经过测试,但那是一般框架。)

答案 1 :(得分:1)

最简单的事情可能是在后台启动它并阻止读取它的输出。类似的东西:

{ start-server-command & } | {
  while read -r line; do
    echo "$line"
    echo "$line" | grep -q 'Server started' && break
  done
  cat &
}
echo script continues here after server outputs 'Server started' message

但这是一个非常难看的黑客。如果可以修改服务器以执行脚本可以等待的更具体的操作,那会更好。