所以我有一个bash命令来启动一个服务器,它输出一些行,然后输出“服务器启动,按Control + C退出”之类的东西。我如何管道这个输出,所以当这一行出现时我把这个过程放在后台并继续使用另一个脚本/函数(即做一些需要等到服务器启动的东西,比如运行测试)
我想最终得到3个功能
我有以下几点:
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?
先谢谢,我对此很陌生。
答案 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
但这是一个非常难看的黑客。如果可以修改服务器以执行脚本可以等待的更具体的操作,那会更好。