我有一个在unix中运行的程序(我无法控制),当完成打印“已成功完成”但未退出时。我想自动检测进程何时完成(通过检查命令的输出),以便我可以终止进程,以便我可以继续进行其他活动。复杂性是因为我希望能够同时运行这些脚本的多个。 (我需要做的一项活动要求使用各种输入调用脚本,但每次脚本运行时都需要一段时间才能返回,因此我想并行执行这些操作)
有人做过类似的事吗? 我可以将命令的stderr和stdout输出重定向到具有随机文件名的临时文件,然后将文件和管道尾随grep以查找结束条件(即某些日志行)。问题是,tail -f肯定会继续运行,所以它永远不会退出。我应该投票吗?如果是这样,最好的方法是什么?
答案 0 :(得分:2)
您无需轮询。您可以使用inotify工具(例如inotifywait)来检测输出文件何时更改,然后grep它并在必要时终止该过程。快乐狩猎!
答案 1 :(得分:2)
#!的/ usr / bin中/期望
spawn / home / foo / myjob
期待“成功完成”
答案 2 :(得分:1)
这是我的尝试,它工作得很好,但是相当垃圾,因为每次kill被称为一个被杀死的消息,回显整个子shell脚本输出到控制台,我似乎无法抑制它。如果我找到摆脱垃圾邮件的方法,我会更新,(顺便说一下,将stdout和stderr重定向到/ dev / null没有帮助。)
注意:你需要bash4来运行它; $BASHPID
仅从4开始提供,$$
不是替代品,因为它提供了父shell的pid,而不是子shell。
!/bin/bash
for i in {1..8}; do
(
mypid=$BASHPID
(
#subshell to simulate started process
sleep 2
echo finished
while : ; do
:
done
) | \
{
while read line; do
if [[ $line == finished ]]; then
break;
fi
done
echo process done, killing $mypid...
kill -9 $mypid
}
) &
done
wait
答案 3 :(得分:1)
以下包装器脚本将调用您的实际命令,将输出管道输出到 tee ,它将写入fifo。当期望字符串来自fifo的 greped 时,包装器脚本将终止您的实际命令:
#!/bin/bash
# cmd to run
expected_output=$1
shift
cmd=("$@")
# where to read commands output
mkfifo /tmp/killonoutput.$$
# start cmd async
"${cmd[@]}"|tee /tmp/killonoutput.$$ 2>/dev/null &
if grep -q --max-count=1 "$expected_output" /tmp/killonoutput.$$;then
kill %1
echo "Killed ${cmd[@]}"
fi
# grep returned so fifo was closed
rm /tmp/killonoutput.$$
示例执行:
./killonoutput.sh "Finished" bash -c "echo sleeping;sleep 3;echo Finished; sleep 10000"
sleeping
Finished
Killed bash -c echo sleeping;sleep 3;echo Finished; sleep 10000
./killonoutput.sh: line 17: 19553 Terminated "${cmd[@]}"
19554 | tee /tmp/killonoutput.$$ 2> /dev/null
答案 4 :(得分:0)
subprocess
模块在您自己的程序和子脚本之间保持通信通道打开。更好的是,您可以使用threading
模块并行启动子脚本的多次运行。
脚本在输出“成功完成”后输出任何内容吗?如果没有,你可以只查询它已经输出的最后x个字符(对于你建议的随机文件,可能使用tail -n 1
来获取最后一行)并查看你是否刚刚看到“已成功完成”。但是如果剧本之后继续打印东西,你可能会错过这条线。
或者您可以grep
在输出中“成功完成”。
答案 5 :(得分:0)
一些随意的想法。 (1)如果它是你的程序,你可以修改它以更有用地表明完成。 (2)查看进程列表(ps ax),当它尝试输出“已完成”消息时,您应该能够看到它进入I / O等待。 (3)我认为伪tty是为了这个目的而存在的,你可以直接观看它们的标准,而不必用临时文件进行清理。
答案 6 :(得分:0)
第一种可能的解决方案:
your_program> tempfile1 强>
grep -i“已成功完成”tempfile1;如果[$? -eq 0];然后我=`pidof your_program`;杀死我; fi
首先是重定向。第二次检查grep的退出状态。如果它是0(成功)它将获得你的程序的pid并杀死它。
这是一次“思维敏捷”的练习。它应该工作。缺点是您一次只能运行一个程序实例,但当然可以进行调整,也可以并行运行。
编辑27.05.2010:
第二种可能解决方案:
tail --pid =`pidof your_program` -f -n0 tempfile1 | awk'/已完成/ {if($ 1 ==“已完成”){system(“i =`pidof your_program`; kill $ i”)}}'&
好吧,有了这条长行,你就不再需要一个loop / crontab了。说明:
--pid =`pidof your_program`在指定的PID结束后使尾部死亡。这样,当程序被杀死时,尾巴就会随之死亡
-n0忽略tempfile1中的其他“已完成”语句(因此您不必担心总是先截断tempfile1)。
awk搜索程序抛出的“已完成”语句,{system}
部分对您的程序执行kill。
最后也不要忘记&
,因为它背景了整个事物
玩得开心。