从shell脚本输出给定行后杀死程序


15

背景:

我正在为一个计算生物学软件编写测试脚本。我正在测试的软件可能需要花费几天甚至几周的时间才能运行,因此它内置了恢复功能,以防系统崩溃或电源故障。

我试图弄清楚如何测试恢复系统。具体来说,我无法找到一种以受控方式“崩溃”程序的方法。我正在考虑以某种方式计时SIGKILL指令在一段时间后才能运行。这可能不是理想的,因为不能保证测试用例每次都以相同的速度运行(在共享环境中运行),因此很难将日志与所需的输出进行比较。

该软件会在完成的每个分析部分打印一行。

题:

我想知道是否有一种良好/优雅的方法(在Shell脚本中)捕获程序的输出,然后在程序输出给定的行数/行数时杀死该程序?


1
为什么需要在特定时间停止程序?由于输出缓冲,在输出要检查的文本后,您可能会长时间终止程序。
stardt

@stardt我想在特定时间停止该程序,以便更好地控制和再现测试结果。我现在已经找到解决方法。我将只手动杀死该程序一次,然后仅测试恢复代码。所有恢复尝试都将从同一点开始。我正在测试它是如何恢复的,而不是它到底是如何崩溃的:)
保罗

Answers:


7

这样的包装脚本是一种标准方法。该脚本在后台运行该程序,然后循环运行,每分钟检查日志文件中是否包含某些字符串。如果找到该字符串,则后台程序被杀死,脚本退出。

command="prog -foo -whatever"
log="prog.log"
match="this is the what i want to match"

$command > "$log" 2>&1 &
pid=$!

while sleep 60
do
    if fgrep --quiet "$match" "$log"
    then
        kill $pid
        exit 0
    fi
done

15

如果您的程序将在SIGPIPE上终止(这是默认操作),则应足以将输出通过管道传递到读取器,该读取器将在读取该行时退出。

所以它可能很简单

$ program | sed -e '/Suitable text from the line/q'

如果要取消默认输出,请使用

$ program | sed -n -e '/Suitable text from the line/q'

同样,如果要在一定数量的行之后停止,则可以使用head代替sed,例如

$ program | head -n$NUMBER_OF_LINES_TO_STOP_AFTER

如注释中的stardt所建议的,终止发生的确切时间确实取决于终端的缓冲行为。


-1。这里有一个严重的缺陷。该程序仅在(如果)终止后尝试写入(断开的)管道时sed终止。OP说:“该软件确实在完成的每个分析部分打印一行”。这可能意味着该程序将完成一个额外的部分!概念证明:{ echo 1; sleep 3; >&2 echo peekaboo; sleep 3; echo 2; } | sed -e '/1/q'。看到这个答案。可能的解决方法:( program & ) | sed -e '/Suitable text from the line/q'; killall program。让您的答案知道该漏洞,我将撤消我的反对意见。
卡米尔Maciorowski

嗯...的确。而且即使您进行了改进,缓冲问题也不可靠(尽管这会影响我在此处看到的每个解决方案)。我喜欢在可能的情况下使用信号基础结构,但是在某些时候它开始失去它的优雅。也许最好只废弃整个东西。
dmckee ---前主持人小猫,

7

作为dmckee答案的替代方法,还可以使用grep带有-m选项的命令(例如,参见此手册页):

compbio | grep -m 1 "Text to match"

当找到与文本匹配的1行时停止

compbio | grep -v -m 10 "Text to match"

等待10行与给定文本不匹配的行。


3

您可以expect(1)用来观看程序的标准输出,然后对某些模式执行预定义的操作。

#!/usr/bin/env expect

spawn your-program -foo -bar 
expect "I want this text" { close }

或将一线式嵌入到另一个脚本中:

expect -c "spawn your-program -foo -bar; expect \"I want this text\" { close }"

请注意,expect默认情况下并非每个操作系统都附带命令。您可能需要安装它。


这是很好的解决方案。我建议提及set timeout -1设置不确定的超时,否则它将在expect的默认10s超时下全部关闭。
pepper_chico

1

您可以使用“ while”语句:

您需要通过管道传输软件(或其日志)的输出,然后对于每行新代码,进行条件测试,然后运行kill -KILL。例如(我使用/ var / log / messages作为日志文件进行了测试):

tail -f /var/log/messages | while read line; do test "$line" = "THE LINE YOU WANT TO MATCH" && kill PIDTOKILL; done

或直接使用软件:

./biosoftware | while read line; do test "$line" = "THE LINE YOU WANT TO MATCH" && kill PIDTOKILL; done

您需要重新放置日志路径/应用程序名称,要匹配的行以及要杀死的PID(您也可以使用killall)。

祝您的软件好运!

雨果

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.