2013-10-23 34 views
2

因此,我有一个bash命令来启动一个服务器,它输出一些行之前,它输出的东西,如“服务器启动,按Ctrl + 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?

在此先感谢我很新了这一点。

回答

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 

但这是一个非常丑陋的黑客攻击。如果可以修改服务器以执行脚本可以等待的更具体的动作,那将会更好。

+0

这应该工作过,并避免与我的方法轮询问题。尽管隐藏服务器的输出可能会更好,就像临时文件方法一样。 (但我认为我们都同意,“最好”的方法是修复服务器:-)) – torek

+0

绝对修复服务器是正确的方法。正如你在答案中提到的那样,缓冲也是一个问题,我可怕的黑客根本就没有处理这个问题。 –

4

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

“背景”和“前景”被控制端的概念,即,他们与当你键入CTRL + CCTRL会发生什么做+ Z等(哪个进程得到信号),进程是否可以从终端设备读取(“后台”进程得到默认使其停止的SIGTTIN)等等。

看起来很清楚,这与您想要达到的目标无关。相反,你有一个不适合的程序(或程序套件)需要一些特别的窍门:当服务器第一次启动时,它需要一些手持到某个点,然后就可以了。一旦输出一些文本字符串,手持可以停止(请参阅您的相关问题或下面的技术)。

这里有一个很大的潜在的问题:很多程序,当其输出重定向到一个管道或文件,产生没有输出,直到他们已经打印输出的“块”的价值,或者退出。如果是这种情况,一个简单的:

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用于测试的过程中是否仍然存在;如果没有,它已经退出了“清理” kill -INT会产生错误信息,但是这可能OK如果没有,要么重定向kill命令的错误输出,或者调整清理或手动执行,如下所示。)

此时,服务器正在运行,您可以执行测试。当你想让它退出,就好像用户点击了ctrl + C,发送一个SIGINTkill -INT

由于有一个在trap集,用于当脚本退出kill -INT(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 

将是适当的。

(显然没有上面的测试,但是这是总体框架。)