自动终止某个命令的命令行命令在一定时间后。

60

我想要在特定时间后自动杀掉一个命令。我考虑的界面如下:

% constrain 300 ./foo args

有一个问题,如何在5分钟后自动杀掉"./foo"进程,但如果该进程占用过多内存也会自动杀掉。

是否有现成的工具或者有人编写过这样的工具?

补充:Jonathan的解决方案完全符合我所想,并且在linux上运行良好,但是我无法使其在Mac OSX上运行。我去掉了SIGRTMIN,可以正常编译,但信号没有被发送到子进程中。有人知道如何在Mac上实现这个功能吗?

[添加:来自Jonathan的更新版可在Mac和其他系统上使用]


你的问题是什么? - Daren Thomas
是的,真的。您在这里并没有提出问题。 - mmcdole
1
类似的问题,有一些不同的答案:stackoverflow.com/questions/687948 - system PAUSE
1
链接到 http://unix.stackexchange.com/questions/21542/from-shell-killing-a-process-if-wallclock-runtime-exceeds-some-predetermined-va/21544#comment111350_21544 - Etienne Low-Décarie
可能是如何在Bash中给定超时后终止子进程?的重复问题。虽然它要求对问题主体进行概括,但“超时”已经成为主导因素,我认为最好针对每个问题提出一个具体的概括。 - Ciro Santilli OurBigBook.com
15个回答

2

纯Bash:


#!/bin/bash

if [[ $# < 2 ]]; then
  echo "Usage: $0 timeout cmd [options]"
  exit 1
fi

TIMEOUT="$1"
shift

BOSSPID=$$

(
  sleep $TIMEOUT
  kill -9 -$BOSSPID
)&
TIMERPID=$!

trap "kill -9 $TIMERPID" EXIT

eval "$@"

2

可以尝试如下操作:

# This function is called with a timeout (in seconds) and a pid.
# After the timeout expires, if the process still exists, it attempts
# to kill it.
function timeout() {
    sleep $1
    # kill -0 tests whether the process exists
    if kill -0 $2 > /dev/null 2>&1 ; then
        echo "killing process $2"
        kill $2 > /dev/null 2>&1
    else
        echo "process $2 already completed"
    fi
}

<your command> &
cpid=$!
timeout 3 $cpid
wait $cpid > /dev/null 2>&
exit $?

这种方法的缺点是,如果在超时期间内您的进程pid被重复使用,可能会误杀掉错误的进程。虽然这种情况非常不太可能发生,但如果您每秒启动20,000个以上的进程,则可能会出现这种情况。这个问题可以得到解决。


2

1

有没有一种使用“at”设置特定时间来执行此操作的方法?

$ at 05:00 PM kill -9 $pid

看起来简单多了。

如果你不知道pid号将是什么,我猜应该有一种方法可以使用ps aux和grep命令来读取它,但是不确定如何实现。

$   | grep someprogram
tony     11585  0.0  0.0   3116   720 pts/1    S+   11:39   0:00 grep someprogram
tony     22532  0.0  0.9  27344 14136 ?        S    Aug25   1:23 someprogram

你的脚本需要读取pid并将其赋值给一个变量。 我不是特别熟练,但假设这是可行的。


1
一个轻微的Perl单行命令修改将正确获取退出状态。
perl -e '$s = shift; $SIG{ALRM} = sub { print STDERR "Timeout!\n"; kill INT => $p; exit 77 }; exec(@ARGV) unless $p = fork; alarm $s; waitpid $p, 0; exit ($? >> 8)' 10 yes foo

基本上,exit($? >> 8)将转发子进程的退出状态。我只选择了超时的退出状态为77。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接