命令行命令在一定时间后自动终止命令

发布于 2024-07-14 07:37:36 字数 413 浏览 11 评论 0原文

我想在一段时间后自动终止命令。 我想到了这样的界面:

% constrain 300 ./foo args

它将使用“args”运行“./foo”,但如果它在 5 分钟后仍在运行,则会自动终止它。

将这个想法推广到其他约束可能会很有用,例如如果进程使用太多内存,则自动终止该进程。

是否有现有的工具可以做到这一点,或者有人写过这样的东西吗?

添加:乔纳森的解决方案正是我想要的,它在 Linux 上工作起来就像一个魅力,但我无法让它在 Mac OSX 上工作。 我摆脱了 SIGRTMIN,它可以很好地编译,但信号不会发送到子进程。 有人知道如何在 Mac 上实现此功能吗?

[补充:请注意,Jonathan 提供了适用于 Mac 和其他地方的更新。]

I'd like to automatically kill a command after a certain amount of time. I have in mind an interface like this:

% constrain 300 ./foo args

Which would run "./foo" with "args" but automatically kill it if it's still running after 5 minutes.

It might be useful to generalize the idea to other constraints, such as autokilling a process if it uses too much memory.

Are there any existing tools that do that, or has anyone written such a thing?

ADDED: Jonathan's solution is precisely what I had in mind and it works like a charm on linux, but I can't get it to work on Mac OSX. I got rid of the SIGRTMIN which lets it compile fine, but the signal just doesn't get sent to the child process. Anyone know how to make this work on Mac?

[Added: Note that an update is available from Jonathan that works on Mac and elsewhere.]

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

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

发布评论

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

评论(15

放肆 2024-07-21 07:37:37

没有办法用“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 并为其分配一个变量。
我不太熟练,但假设这是可行的。

Isn't there a way to set a specific time with "at" to do this?

$ at 05:00 PM kill -9 $pid

Seems a lot simpler.

If you don't know what the pid number is going to be, I assume there's a way to script reading it with ps aux and grep, but not sure how to implement that.

$   | 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

Your script would have to read the pid and assign it a variable.
I'm not overly skilled, but assume this is doable.

惜醉颜 2024-07-21 07:37:36

GNU Coreutils 包含 timeout 命令,许多系统上默认安装该命令。

https://www.gnu.org/software/coreutils/manual /html_node/timeout-invocation.html

要监视 free -m 一分钟,然后通过发送 TERM 信号来终止它:

timeout 1m watch free -m

GNU Coreutils includes the timeout command, installed by default on many systems.

https://www.gnu.org/software/coreutils/manual/html_node/timeout-invocation.html

To watch free -m for one minute, then kill it by sending a TERM signal:

timeout 1m watch free -m
你与昨日 2024-07-21 07:37:36

也许我不理解这个问题,但这听起来直接可行,至少在 bash 中:

( /path/to/slow command with options ) & sleep 5 ; kill $!

这会运行括号内的第一个命令五秒钟,然后终止它。 整个操作同步运行,即当 shell 忙于等待缓慢的命令时,您将无法使用 shell。 如果这不是您想要的,应该可以添加另一个 &。

$! 变量是 Bash 内置变量,其中包含最近启动的子 shell 的进程 ID。 重要的是不要有 & 在括号内,这样做会丢失进程 ID。

Maybe I'm not understanding the question, but this sounds doable directly, at least in bash:

( /path/to/slow command with options ) & sleep 5 ; kill $!

This runs the first command, inside the parenthesis, for five seconds, and then kills it. The entire operation runs synchronously, i.e. you won't be able to use your shell while it is busy waiting for the slow command. If that is not what you wanted, it should be possible to add another &.

The $! variable is a Bash builtin that contains the process ID of the most recently started subshell. It is important to not have the & inside the parenthesis, doing it that way loses the process ID.

梦里梦着梦中梦 2024-07-21 07:37:36

我参加这个聚会已经很晚了,但我没有看到答案中列出我最喜欢的技巧。

在 *NIX 下,alarm(2) 是通过 execve(2) 继承的,并且 SIGALRM 默认情况下是致命的。 因此,您通常可以简单地:

$ doalarm () { perl -e 'alarm shift; exec @ARGV' "$@"; } # define a helper function

$ doalarm 300 ./foo.sh args

或安装一个 简单的 C 包装器 来为您做到这一点。

优点 只涉及一个PID,机制简单。 例如,如果 ./foo.sh 退出“太快”并且其 PID 被重新使用,您就不会杀死错误的进程。 您不需要多个 shell 子进程协同工作,这可以正确完成,但很容易出现竞争。

缺点 时间受限的进程无法操作其闹钟(例如,alarm(2)ualarm(2)setitimer( 2)),因为这可能会清除继承的警报。 显然,它也不能阻止或忽略 SIGALRM,尽管对于其他一些方法来说,SIGINT、SIGTERM 等也是如此。

一些(我认为是非常古老的)系统根据 alarm(2) 实现 sleep(2),并且即使在今天,一些程序员也使用 alarm(2) ) 作为 I/O 和其他操作的粗略内部超时机制。 然而,根据我的经验,这种技术适用于您想要限制时间的绝大多数流程。

I've arrived rather late to this party, but I don't see my favorite trick listed in the answers.

Under *NIX, an alarm(2) is inherited across an execve(2) and SIGALRM is fatal by default. So, you can often simply:

$ doalarm () { perl -e 'alarm shift; exec @ARGV' "$@"; } # define a helper function

$ doalarm 300 ./foo.sh args

or install a trivial C wrapper to do that for you.

Advantages Only one PID is involved, and the mechanism is simple. You won't kill the wrong process if, for example, ./foo.sh exited "too quickly" and its PID was re-used. You don't need several shell subprocesses working in concert, which can be done correctly but is rather race-prone.

Disadvantages The time-constrained process cannot manipulate its alarm clock (e.g., alarm(2), ualarm(2), setitimer(2)), since this would likely clear the inherited alarm. Obviously, neither can it block or ignore SIGALRM, though the same can be said of SIGINT, SIGTERM, etc. for some other approaches.

Some (very old, I think) systems implement sleep(2) in terms of alarm(2), and, even today, some programmers use alarm(2) as a crude internal timeout mechanism for I/O and other operations. In my experience, however, this technique is applicable to the vast majority of processes you want to time limit.

失与倦" 2024-07-21 07:37:36

还有ulimit,可用于限制子进程可用的执行时间。

ulimit -t 10

将进程的 CPU 时间限制为 10 秒。

要实际使用它来限制新进程而不是当前进程,您可能希望使用包装脚本:

#! /usr/bin/env python

import os
os.system("ulimit -t 10; other-command-here")

other-command 可以是任何工具。 我正在运行不同排序算法的 Java、Python、C 和 Scheme 版本,并记录它们花费的时间,同时将执行时间限制为 30 秒。 Cocoa-Python 应用程序生成了各种命令行(包括参数)并将时间整理到 CSV 文件中,但它实际上只是上面提供的命令之上的一些内容。

There is also ulimit, which can be used to limit the execution time available to sub-processes.

ulimit -t 10

Limits the process to 10 seconds of CPU time.

To actually use it to limit a new process, rather than the current process, you may wish to use a wrapper script:

#! /usr/bin/env python

import os
os.system("ulimit -t 10; other-command-here")

other-command can be any tool. I was running a Java, Python, C and Scheme versions of different sorting algorithms, and logging how long they took, whilst limiting execution time to 30 seconds. A Cocoa-Python application generated the various command lines - including the arguments - and collated the times into a CSV file, but it was really just fluff on top of the command provided above.

孤凫 2024-07-21 07:37:36

我有一个名为 timeout 的程序,它是用 C 语言编写的,最初是在 1989 年,但从那时起定期更新。


Update: this code fails to compile on MacOS X because SIGRTMIN is not defined, and fails to timeout when run on MacOS X because the `signal()` function there resumes the `wait()` after the alarm times out - which is not the required behaviour. I have a new version of `timeout.c` which deals with both these problems (using `sigaction()` instead of `signal()`). As before, contact me for a 10K gzipped tar file with the source code and a manual page (see my profile).


/*
@(#)File:           $RCSfile: timeout.c,v $
@(#)Version:        $Revision: 4.6 $
@(#)Last changed:   $Date: 2007/03/01 22:23:02 $
@(#)Purpose:        Run command with timeout monitor
@(#)Author:         J Leffler
@(#)Copyright:      (C) JLSS 1989,1997,2003,2005-07
*/

#define _POSIX_SOURCE       /* Enable kill() in <unistd.h> on Solaris 7 */
#define _XOPEN_SOURCE 500

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "stderr.h"

#define CHILD       0
#define FORKFAIL    -1

static const char usestr[] = "[-vV] -t time [-s signal] cmd [arg ...]";

#ifndef lint
/* Prevent over-aggressive optimizers from eliminating ID string */
const char jlss_id_timeout_c[] = "@(#)$Id: timeout.c,v 4.6 2007/03/01 22:23:02 jleffler Exp $";
#endif /* lint */

static void catcher(int signum)
{
    return;
}

int main(int argc, char **argv)
{
    pid_t   pid;
    int     tm_out;
    int     kill_signal;
    pid_t   corpse;
    int     status;
    int     opt;
    int     vflag = 0;

    err_setarg0(argv[0]);

    opterr = 0;
    tm_out = 0;
    kill_signal = SIGTERM;
    while ((opt = getopt(argc, argv, "vVt:s:")) != -1)
    {
        switch(opt)
        {
        case 'V':
            err_version("TIMEOUT", &"@(#)$Revision: 4.6 $ ($Date: 2007/03/01 22:23:02 $)"[4]);
            break;
        case 's':
            kill_signal = atoi(optarg);
            if (kill_signal <= 0 || kill_signal >= SIGRTMIN)
                err_error("signal number must be between 1 and %d\n", SIGRTMIN - 1);
            break;
        case 't':
            tm_out = atoi(optarg);
            if (tm_out <= 0)
                err_error("time must be greater than zero (%s)\n", optarg);
            break;
        case 'v':
            vflag = 1;
            break;
        default:
            err_usage(usestr);
            break;
        }
    }

    if (optind >= argc || tm_out == 0)
        err_usage(usestr);

    if ((pid = fork()) == FORKFAIL)
        err_syserr("failed to fork\n");
    else if (pid == CHILD)
    {
        execvp(argv[optind], &argv[optind]);
        err_syserr("failed to exec command %s\n", argv[optind]);
    }

    /* Must be parent -- wait for child to die */
    if (vflag)
        err_remark("time %d, signal %d, child PID %u\n", tm_out, kill_signal, (unsigned)pid);
    signal(SIGALRM, catcher);
    alarm((unsigned int)tm_out);
    while ((corpse = wait(&status)) != pid && errno != ECHILD)
    {
        if (errno == EINTR)
        {
            /* Timed out -- kill child */
            if (vflag)
                err_remark("timed out - send signal %d to process %d\n", (int)kill_signal, (int)pid);
            if (kill(pid, kill_signal) != 0)
                err_syserr("sending signal %d to PID %d - ", kill_signal, pid);
            corpse = wait(&status);
            break;
        }
    }

    alarm(0);
    if (vflag)
    {
        if (corpse == (pid_t) -1)
            err_syserr("no valid PID from waiting - ");
        else
            err_remark("child PID %u status 0x%04X\n", (unsigned)corpse, (unsigned)status);
    }

    if (corpse != pid)
        status = 2; /* I don't know what happened! */
    else if (WIFEXITED(status))
        status = WEXITSTATUS(status);
    else if (WIFSIGNALED(status))
        status = WTERMSIG(status);
    else
        status = 2; /* I don't know what happened! */

    return(status);
}

如果您想要“stderr.h”和“stderr.c”的“官方”代码,请与我联系(请参阅我的个人资料)。

I have a program called timeout that does that - written in C, originally in 1989 but updated periodically since then.


Update: this code fails to compile on MacOS X because SIGRTMIN is not defined, and fails to timeout when run on MacOS X because the `signal()` function there resumes the `wait()` after the alarm times out - which is not the required behaviour. I have a new version of `timeout.c` which deals with both these problems (using `sigaction()` instead of `signal()`). As before, contact me for a 10K gzipped tar file with the source code and a manual page (see my profile).


/*
@(#)File:           $RCSfile: timeout.c,v $
@(#)Version:        $Revision: 4.6 $
@(#)Last changed:   $Date: 2007/03/01 22:23:02 $
@(#)Purpose:        Run command with timeout monitor
@(#)Author:         J Leffler
@(#)Copyright:      (C) JLSS 1989,1997,2003,2005-07
*/

#define _POSIX_SOURCE       /* Enable kill() in <unistd.h> on Solaris 7 */
#define _XOPEN_SOURCE 500

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "stderr.h"

#define CHILD       0
#define FORKFAIL    -1

static const char usestr[] = "[-vV] -t time [-s signal] cmd [arg ...]";

#ifndef lint
/* Prevent over-aggressive optimizers from eliminating ID string */
const char jlss_id_timeout_c[] = "@(#)$Id: timeout.c,v 4.6 2007/03/01 22:23:02 jleffler Exp 
quot;;
#endif /* lint */

static void catcher(int signum)
{
    return;
}

int main(int argc, char **argv)
{
    pid_t   pid;
    int     tm_out;
    int     kill_signal;
    pid_t   corpse;
    int     status;
    int     opt;
    int     vflag = 0;

    err_setarg0(argv[0]);

    opterr = 0;
    tm_out = 0;
    kill_signal = SIGTERM;
    while ((opt = getopt(argc, argv, "vVt:s:")) != -1)
    {
        switch(opt)
        {
        case 'V':
            err_version("TIMEOUT", &"@(#)$Revision: 4.6 $ ($Date: 2007/03/01 22:23:02 $)"[4]);
            break;
        case 's':
            kill_signal = atoi(optarg);
            if (kill_signal <= 0 || kill_signal >= SIGRTMIN)
                err_error("signal number must be between 1 and %d\n", SIGRTMIN - 1);
            break;
        case 't':
            tm_out = atoi(optarg);
            if (tm_out <= 0)
                err_error("time must be greater than zero (%s)\n", optarg);
            break;
        case 'v':
            vflag = 1;
            break;
        default:
            err_usage(usestr);
            break;
        }
    }

    if (optind >= argc || tm_out == 0)
        err_usage(usestr);

    if ((pid = fork()) == FORKFAIL)
        err_syserr("failed to fork\n");
    else if (pid == CHILD)
    {
        execvp(argv[optind], &argv[optind]);
        err_syserr("failed to exec command %s\n", argv[optind]);
    }

    /* Must be parent -- wait for child to die */
    if (vflag)
        err_remark("time %d, signal %d, child PID %u\n", tm_out, kill_signal, (unsigned)pid);
    signal(SIGALRM, catcher);
    alarm((unsigned int)tm_out);
    while ((corpse = wait(&status)) != pid && errno != ECHILD)
    {
        if (errno == EINTR)
        {
            /* Timed out -- kill child */
            if (vflag)
                err_remark("timed out - send signal %d to process %d\n", (int)kill_signal, (int)pid);
            if (kill(pid, kill_signal) != 0)
                err_syserr("sending signal %d to PID %d - ", kill_signal, pid);
            corpse = wait(&status);
            break;
        }
    }

    alarm(0);
    if (vflag)
    {
        if (corpse == (pid_t) -1)
            err_syserr("no valid PID from waiting - ");
        else
            err_remark("child PID %u status 0x%04X\n", (unsigned)corpse, (unsigned)status);
    }

    if (corpse != pid)
        status = 2; /* I don't know what happened! */
    else if (WIFEXITED(status))
        status = WEXITSTATUS(status);
    else if (WIFSIGNALED(status))
        status = WTERMSIG(status);
    else
        status = 2; /* I don't know what happened! */

    return(status);
}

If you want the 'official' code for 'stderr.h' and 'stderr.c', contact me (see my profile).

骄兵必败 2024-07-21 07:37:36

Perl one liner,只是为了好玩:

perl -e '$s = shift; $SIG{ALRM} = sub { print STDERR "Timeout!\n"; kill INT => $p }; exec(@ARGV) unless $p = fork; alarm $s; waitpid $p, 0' 10 yes foo

这会打印“foo”十秒钟,然后超时。 将“10”替换为任意秒数,将“yes foo”替换为任意命令。

Perl one liner, just for kicks:

perl -e '$s = shift; $SIG{ALRM} = sub { print STDERR "Timeout!\n"; kill INT => $p }; exec(@ARGV) unless $p = fork; alarm $s; waitpid $p, 0' 10 yes foo

This prints 'foo' for ten seconds, then times out. Replace '10' with any number of seconds, and 'yes foo' with any command.

泪是无色的血 2024-07-21 07:37:36

从源代码编译以在 Mac 上运行时,来自 Ubuntu/Debian 的超时命令。 达尔文

10.4.*

http://packages.ubuntu.com/lucid/timeout

The timeout command from Ubuntu/Debian when compiled from source to work on the Mac. Darwin

10.4.*

http://packages.ubuntu.com/lucid/timeout

心欲静而疯不止 2024-07-21 07:37:36

我对 Perl 单行代码的变体为您提供了退出状态,而无需使用 fork() 和 wait() 进行处理,并且没有杀死错误进程的风险:

#!/bin/sh
# Usage: timelimit.sh secs cmd [ arg ... ]
exec perl -MPOSIX -e '$SIG{ALRM} = sub { print "timeout: @ARGV\n"; kill(SIGTERM, -$); }; alarm shift; $exit = system @ARGV; exit(WIFEXITED($exit) ? WEXITSTATUS($exit) : WTERMSIG($exit));' "$@"

基本上 fork() 和 wait() 隐藏在 system() 内。 SIGALRM 被传递到父进程,然后父进程通过向整个进程组 (-$$) 发送 SIGTERM 来杀死自身及其子进程。 万一子进程退出并且子进程的 pid 在 Kill() 发生之前被重用,这不会杀死错误的进程,因为具有旧子进程 pid 的新进程不会位于父 perl 进程的同一进程组中。

作为一个额外的好处,脚本还可以以可能正确的退出状态退出。

My variation on the perl one-liner gives you the exit status without mucking with fork() and wait() and without the risk of killing the wrong process:

#!/bin/sh
# Usage: timelimit.sh secs cmd [ arg ... ]
exec perl -MPOSIX -e '$SIG{ALRM} = sub { print "timeout: @ARGV\n"; kill(SIGTERM, -$); }; alarm shift; $exit = system @ARGV; exit(WIFEXITED($exit) ? WEXITSTATUS($exit) : WTERMSIG($exit));' "$@"

Basically the fork() and wait() are hidden inside system(). The SIGALRM is delivered to the parent process which then kills itself and its child by sending SIGTERM to the whole process group (-$$). In the unlikely event that the child exits and the child's pid gets reused before the kill() occurs, this will NOT kill the wrong process because the new process with the old child's pid will not be in the same process group of the parent perl process.

As an added benefit, the script also exits with what is probably the correct exit status.

故事还在继续 2024-07-21 07:37:36
#!/bin/sh
( some_slow_task ) & pid=$!
( sleep $TIMEOUT && kill -HUP $pid ) 2>/dev/null & watcher=$!
wait $pid 2>/dev/null && pkill -HUP -P $watcher

观察者在给定的超时后终止缓慢的任务; 该脚本等待缓慢的任务并终止观察者。

示例:

  • 慢任务运行超过 2 秒并被终止

慢速任务被中断

( sleep 20 ) & pid=$!
( sleep 2 && kill -HUP $pid ) 2>/dev/null & watcher=$!
if wait $pid 2>/dev/null; then
    echo "Slow task finished"
    pkill -HUP -P $watcher
    wait $watcher
else
    echo "Slow task interrupted"
fi
  • 该慢速任务在给定超时之前完成

缓慢的任务完成

( sleep 2 ) & pid=$!
( sleep 20 && kill -HUP $pid ) 2>/dev/null & watcher=$!
if wait $pid 2>/dev/null; then
    echo "Slow task finished"
    pkill -HUP -P $watcher
    wait $watcher
else
    echo "Slow task interrupted"
fi
#!/bin/sh
( some_slow_task ) & pid=$!
( sleep $TIMEOUT && kill -HUP $pid ) 2>/dev/null & watcher=$!
wait $pid 2>/dev/null && pkill -HUP -P $watcher

The watcher kills the slow task after given timeout; the script waits for the slow task and terminates the watcher.

Examples:

  • The slow task run more than 2 sec and was terminated

Slow task interrupted

( sleep 20 ) & pid=$!
( sleep 2 && kill -HUP $pid ) 2>/dev/null & watcher=$!
if wait $pid 2>/dev/null; then
    echo "Slow task finished"
    pkill -HUP -P $watcher
    wait $watcher
else
    echo "Slow task interrupted"
fi
  • This slow task finished before the given timeout

Slow task finished

( sleep 2 ) & pid=$!
( sleep 20 && kill -HUP $pid ) 2>/dev/null & watcher=$!
if wait $pid 2>/dev/null; then
    echo "Slow task finished"
    pkill -HUP -P $watcher
    wait $watcher
else
    echo "Slow task interrupted"
fi
清引 2024-07-21 07:37:36

尝试如下操作:

# 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,则可能会杀死错误的进程。 这种情况不太可能发生,但您可能每秒启动 20000 多个进程。 这可以解决。

Try something like:

# 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 $?

It has the downside that if your process' pid is reused within the timeout, it may kill the wrong process. This is highly unlikely, but you may be starting 20000+ processes per second. This could be fixed.

紙鸢 2024-07-21 07:37:36

使用expect工具怎么样?

## run a command, aborting if timeout exceeded, e.g. timed-run 20 CMD ARGS ...
timed-run() {
  # timeout in seconds
  local tmout="$1"
  shift
  env CMD_TIMEOUT="$tmout" expect -f - "$@" <<"EOF"
# expect script follows
eval spawn -noecho $argv
set timeout $env(CMD_TIMEOUT)
expect {
   timeout {
      send_error "error: operation timed out\n"
      exit 1
   }
   eof
}
EOF
}

How about using the expect tool?

## run a command, aborting if timeout exceeded, e.g. timed-run 20 CMD ARGS ...
timed-run() {
  # timeout in seconds
  local tmout="$1"
  shift
  env CMD_TIMEOUT="$tmout" expect -f - "$@" <<"EOF"
# expect script follows
eval spawn -noecho $argv
set timeout $env(CMD_TIMEOUT)
expect {
   timeout {
      send_error "error: operation timed out\n"
      exit 1
   }
   eof
}
EOF
}
后来的我们 2024-07-21 07:37:36

纯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 "$@"

pure 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 "$@"
自在安然 2024-07-21 07:37:36

我使用“timelimit”,它是 debian 存储库中提供的一个包。

http://devel.ringlet.net/sysutils/timelimit/

I use "timelimit", which is a package available in the debian repository.

http://devel.ringlet.net/sysutils/timelimit/

痴情换悲伤 2024-07-21 07:37:36

对 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超时。

A slight modification of the perl one-liner will get the exit status right.

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

Basically, exit ($? >> 8) will forward the exit status of the subprocess. I just chose 77 at the exit status for timeout.

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