检测进程何时完成(但未退出)

时间:2010-04-22 07:40:07

标签: bash exit polling

我有一个在unix中运行的程序(我无法控制),当完成打印“已成功完成”但未退出时。我想自动检测进程何时完成(通过检查命令的输出),以便我可以终止进程,以便我可以继续进行其他活动。复杂性是因为我希望能够同时运行这些脚本的多个。 (我需要做的一项活动要求使用各种输入调用脚本,但每次脚本运行时都需要一段时间才能返回,因此我想并行执行这些操作)

有人做过类似的事吗? 我可以将命令的stderr和stdout输出重定向到具有随机文件名的临时文件,然后将文件和管道尾随grep以查找结束条件(即某些日志行)。问题是,tail -f肯定会继续运行,所以它永远不会退出。我应该投票吗?如果是这样,最好的方法是什么?

7 个答案:

答案 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)

对于bash来说这可能有点过分了,也许吧?如果您使用的是python,则可以使用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。
最后也不要忘记&,因为它背景了整个事物 玩得开心。