Elimina automaticamente o processo se seu tempo de execução exceder algum valor predeterminado

5

Eu quero iniciar um processo a partir de um script de shell, permitir que ele interaja com o usuário (não posso apenas fazer o background, pegar o PID, lançar sleep seguido de verificações de integridade e kill ), mas se ainda está em execução depois de um período de tempo definido (digamos, dois minutos), então e só então eu quero matá-lo.

A intenção é simplesmente implementar um timeout wallclock-run-time para um programa que não tenha esse recurso embutido.

Existe uma maneira de fazer isso, de preferência de um script de shell bash?

    
por a CVn 27.09.2011 / 21:11

2 respostas

6

BASH FAQ entry # 68: "Como faço para executar um comando e abortar (timeout) após N segundos?" / a>

FIRST check whether the command you're running can be told to timeout directly. The methods described here are "hacky" workarounds to force a command to terminate after a certain time has elapsed. Configuring your command properly is always preferable to the alternatives below.

If the command has no native support for stopping after a specified time, then the best alternatives are some external commands called timeout and doalarm. Some Linux distributions offer the tct version of timeout as a package. There is also a GNU version of timeout, included in recent coreutils releases.

Beware: by default, some implementations of timeout issue a SIGKILL (kill -9), which is roughly the same as pulling out the power cord (leaving no chance for the program to commit its work, often resulting in corruption of its data). You should use a signal that allows the program to shut itself down instead (SIGTERM). See ProcessManagement for more information on SIGKILL.

The primary difference between doalarm and timeout is that doalarm "execs" the program after setting up the alarm, which makes it wonderful in a WrapperScript; while timeout launches the program as a child and then hangs around (both processes exist simultaneously), which gives it the opportunity to send more than one signal if necessary.

If you don't have or don't want one of the above programs, you can use a perl one-liner to set an ALRM and then exec the program you want to run under a time limit. In any case, you must understand what your program does with SIGALRM; programs with periodic updates usually use ALRM for that purpose and update rather than dying when they receive that signal.

doalarm() { perl -e 'alarm shift; exec @ARGV' "$@"; }

doalarm ${NUMBER_OF_SECONDS_BEFORE_ALRMING} program arg arg ...

If you can't or won't use one of these programs (which really should have been included with the basic core Unix utilities 30 years ago!), then the best you can do is an ugly hack like:

 command & pid=$!
 { sleep 10; kill $pid; } &

This will, as you will soon discover, produce quite a mess regardless of whether the timeout condition kicked in or not, if it's run in an interactive shell. Cleaning it up is not something worth my time. Also, it can't be used with any command that requires a foreground terminal, like top.

It is possible to do something similar, but to keep command in the foreground:

 bash -c '(sleep 10; kill $$) & exec command'

kill $$ would kill the shell, except that exec causes the command to take over the shell's PID. It is necessary to use bash -c so that the calling shell isn't replaced; in bash 4, it is possible to use a subshell instead:

 ( cmdpid=$BASHPID; (sleep 10; kill $cmdpid) & exec command )

The shell-script "timeout" (not to be confused with the command 'timeout') uses the second approach above. It has the advantage of working immediately (no need for compiling a program), but has problems e.g. with programs reading standard input.

Just use timeout or doalarm instead. Really.

    
por 27.09.2011 / 21:22
4

Em um sistema Linux suficientemente recente (mais precisamente, com GNU coreutils ≥8.5), é tão simples quanto

timeout 2m myprogram

Com apenas recursos de shell POSIX, você pode se aproximar, mas há uma pequena condição de corrida se o tempo limite ocorrer (em teoria, o PID do segundo processo em segundo plano pode ser reutilizado antes de executar kill $s ). p>

myprogram <>/dev/tty & p=$!;
{ sleep 120; kill $p; } & s=$!;
wait $p; kill $s

Existe uma boa maneira de trabalhar mesmo quando você precisa da saída do programa, sem nenhuma condição de corrida. É um truque interessante usar a capacidade de enviar um sinal para os grupos de processos . Isso é devido a Stéphane Gimenez .

sh -ic '{ myprogram <>/dev/tty; kill 0; } |
        { sleep 120; kill 0; }'
    
por 28.09.2011 / 01:12

Tags