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

发布于 2024-08-30 04:33:50 字数 326 浏览 4 评论 0原文

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

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

I have a program that's run in unix (that I have no control over) that when finished prints 'Completed successfully' but does not exit. I want to automatically detect when the process finishes (by checking the output of the command), so that I can kill the process and so that I can proceed do other activities. The complexity comes because I want to be able to run multiples of these scripts concurrently. (One activity I need to do requires the script to be called with various inputs, but each time the script runs it takes a while to return, and so I want to do them in parallel)

Has anyone done something similar to this?
I could redirect the stderr and stdout output of the command to a temporary file which has a random file name, then tail the file and pipe to grep for the end conditions (I.e. the certain log lines). The problem is, surely tail -f would keep running, and so it would never exit. Should I poll? If so, what's the best approach?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

累赘 2024-09-06 04:33:50

#!/usr/bin/expect

spawn /home/foo/myjob
期待“成功完成”

#!/usr/bin/expect

spawn /home/foo/myjob
expect "Completed successfully"

晨曦慕雪 2024-09-06 04:33:50

您不必进行民意调查。您可以使用 inotify 工具,例如 inotifywait,检测输出文件何时发生更改,然后 grep 它并在必要时终止进程。狩猎快乐!

You don't have to poll. You can use inotify tools, such as inotifywait, to detect when the output file has changed, and then grep it and kill the process if necessary. Happy hunting!

甜嗑 2024-09-06 04:33:50

这是我的尝试,它工作得很好,但是相当垃圾邮件,因为每次调用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

Here's my stab at it, it works pretty well, but is rather spammy because each time kill is called a killed message echoing the entire subshell script is output to console and I can't seemt to supress it. I will update if I find a way to get rid of the spammyness, (by the way, redirecting stdout and stderr to /dev/null does not help.)

Note: You need bash4 to run this; $BASHPID is only available from 4 onwards, and $$ is not an alternative because it gives the pid of the parent shell, not the subshell.

!/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
倒带 2024-09-06 04:33:50

以下包装器脚本将调用您的实际命令,将输出通过管道传输到 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

The following wrapper script will call your real command, piping output to tee which will write to a fifo. The wrapper script will kill your real command, when the expected string is greped from the fifo:

#!/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.$

Sample execution:

./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
时光清浅 2024-09-06 04:33:50

这对于 bash 来说可能有点过分了,也许吧?如果您使用的是 python,则可以使用 subprocess 模块在您自己的程序和子脚本之间保持开放的通信通道。更好的是,您可以使用 threading 模块并行启动子脚本的多次运行。

脚本输出“成功完成”后是否输出任何内容?如果没有,您可以轮询它输出的最后 x 个字符(如您建议的那样,到一个随机文件,也许使用 tail -n 1 来获取最后一行),看看您是否刚刚看到 '成功完成'。但如果脚本随后继续打印内容,您可能会错过该行。

或者您可以在输出中 grep 表示“成功完成”。

this might be overkill for bash, maybe? if you were using python, you could use the subprocess module keep a communication channel open between your own program and your child scripts. even better, you could use the threading module to start multiple runs of the child script in parallel.

does the script output anything AFTER it outputs "completed successfully" ? if not, you could just poll for the last x characters it has outputed (to a random file like you suggested, maybe using tail -n 1 to get the last line) and see if you just saw 'completed successfully'. but if the script keeps printing stuff afterwards, you might miss the line.

or you could grep for "completed successfully" in the output.

方觉久 2024-09-06 04:33:50

一些随机的想法。 (1) 如果这是您的程序,您可以修改它以更有用地指示熟度。 (2) 查看进程列表 ( ps ax ),您应该能够看到它在尝试输出“Completed”消息时进入 I/O 等待状态。 (3) 我相信伪 tty 的存在就是为了这个目的,你可以直接观看它们的标准输出,而不必处理临时文件。

A few random ideas. (1) If it's your program, you could modify it to indicate doneness more usefully. (2) Looking at the process list ( ps ax ) you should be able to see it go into an I/O wait when it tries to output the "Completed" message. (3) I believe pseudo tty's exist for this purpose, that you can watch their stdout directly without having to muck about with temporary files.

深陷 2024-09-06 04:33:50

第一个可能的解决方案:
你的程序>临时文件1
grep -i "成功完成" tempfile1;如果 [ $? -eq 0];然后我=`pidof your_program`;杀死$i; fi

首先是重定向。其次检查 grep 的退出状态。如果它是 0(成功),它会获取你的程序的 pid 并杀死它。
这是一个“快速思考”的练习。它应该有效。缺点是您一次只能运行程序的一个实例,但当然可以进行调整,并且可以并行运行它。

编辑-2010年5月27日:
第二种可能的解决方案:
tail --pid=`您的程序的 pid` -f -n0 tempfile1 | awk '/Completed/ {if ($1=="Completed") {system("i=`pidof your_program`;kill $i")}}' &

好吧,有了这么长的一行,你就不需要不再需要循环/crontab了。说明:
--pid=`pidof your_program` 使 tail 在指定的 PID 结束后死亡。这样,当程序被杀死时,tail也随之消失。
-n0 忽略 tempfile1 中的其他“已完成”语句(因此您不必担心总是先截断 tempfile1)。
awk 搜索您的程序抛出的“Completed”语句,并且 {system} 部分对您的程序执行终止操作。
另外,不要忘记最后的 &,因为它是整个内容的背景。
玩得开心。

1st possible solution:
your_program > tempfile1
grep -i "Completed successfully" tempfile1; if [ $? -eq 0 ] ; then i=`pidof your_program`; kill $i; fi

First is redirection. Second checks for the exit status of grep. If it is 0 (success) it gets the pid of your program and kills it.
This was a "think-fast" exercise. It should work. A drawback is that you can only run one instance of your program at a time, but of course an adaptation can be made and you could run it in parallel.

edit-27.05.2010:
2nd possible solution:
tail --pid=`pidof your_program` -f -n0 tempfile1 | awk '/Completed/ {if ($1=="Completed") {system("i=`pidof your_program`; kill $i")}}' &

Well, with this long line you don't need a loop/crontab anymore. Explanation:
--pid=`pidof your_program` makes tail die after the specified PID is ended. This way, when the program gets killed, tail dies along with it.
-n0 ignores other "Completed" statements in tempfile1 (so you don't have to worry to always truncate tempfile1 first).
awk searches for the "Completed" statement thrown out by your program and the {system} part executes the kill on your program.
Also don't forget the & at the end as it backgrounds the entire thing.
Have fun.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文