O que é uma maneira simples de permitir que um comando seja executado por 5 minutos? [duplicado]

59

Existe uma maneira fácil de permitir que um comando específico (somente terminável em Ctrl-C ) seja executado automaticamente por 5 minutos?

Por exemplo:

minute-command 5-minutes ping www.google.com

ou qualquer outro comando que não termine em si.

Gostaria de poder especificar um limite de tempo, não apenas 5 minutos.

    
por eckhart 25.02.2016 / 07:35

6 respostas

61

Existem (pelo menos) dois programas que fornecem essa funcionalidade:

NAME

timelimit — effectively limit the absolute execution time of a process

SYNOPSIS

timelimit [-pq] [-S killsig] [-s warnsig] [-T killtime] [-t warntime] command [arguments ...]

e

NAME

timeout - run a command with a time limit

SYNOPSIS

timeout [OPTION] DURATION COMMAND [ARG]...
timeout [OPTION]

Eles são empacotados da seguinte forma:

$ dlocate 'which timeout timelimit'
timelimit: /usr/bin/timelimit
coreutils: /usr/bin/timeout

Comparação:

/-----------------------------+------------+----------------\
|            Feature          |  timelimit |     timeout    |
+=============================+============+================+
|   time to run               | -t time    | first argument |
+-----------------------------+------------+----------------+
|   terminate signal          | -s signal  | -s signal      |
+-----------------------------+------------+----------------+
|   grace period              | -T time    | -k time        |
+-----------------------------+------------+----------------+
|   kill signal               | -S signal  | (note 1)       |
+-----------------------------+------------+----------------+
|   propagate signals         | -p         | (note 2)       |
\-----------------------------+------------+----------------/

Notas:

  1. timeout sempre usa SIGKILL como sinal de último recurso.
  2. timeout não tem nenhuma funcionalidade para sair com um sinal quando o programa filho faz isso.

O status de saída dos dois programas é diferente, mas isso é difícil de resumir nitidamente, então sugiro que você mesmo consulte as páginas do manual para isso.

Como timeout está instalado em mais sistemas por padrão ( coreutils é um pacote padrão em muitas distribuições), sugiro que você use isso a menos que você precise da funcionalidade extra fornecida por timelimit .

    
por 25.02.2016 / 12:14
86

Na verdade, é para isso que o timeout :

TIMEOUT(1)                          User Commands                         TIMEOUT(1)

NAME
       timeout - run a command with a time limit

SYNOPSIS
       timeout [OPTION] DURATION COMMAND [ARG]...
       timeout [OPTION]

DESCRIPTION
       Start COMMAND, and kill it if still running after DURATION.

lx@lxtp:~$ dpkg -S /usr/bin/timeout
coreutils: /usr/bin/timeout
    
por 25.02.2016 / 08:46
13

bash puro integrado, sem coreutils

Descobri que essa solução funciona em bash confiando em um comando embutido sem chamar um executável externo. Ele funciona no sistema onde, eventualmente, nem sequer foram instalados os coreutils [ 1 ]

YourCommand & read -t 300 ;  kill $!                           # 1st version
YourCommand & read -t 300 || kill $!                           # 2nd version 

Explicações : como de costume quando você envia um comando em segundo plano com & , seu PID é armazenado na variável interna $! (presente na versão moderna de dash , csh , bash , tcsh , zsh ...).
O que realmente faz a diferença entre os shells é a presença do comando built-in read [ 2 ] e da opção -t . Na primeira versão, se o usuário não concluir uma linha de entrada antes da quantidade especificada de segundos, a instrução será finalizada e um código de retorno de erro será gerado.

-t TIMEOUT Cause read to time out and return failure if a complete line of input is not read within TIMEOUT seconds.

A segunda versão funciona como a primeira, mas você pode anular o tempo limite de expiração pressionando enter . Na verdade, o ou operador || executará a instrução kill somente se o comando read sair com um código de retorno diferente de zero, como quando o tempo limite expirou. Se você pressionar enter antes desse momento, ele retornará 0 e não matará seu comando anterior.

Soluções Coreutils [ 1 ]

Quando coreutils estão presentes em seu sistema e você não precisa economizar tempo e recursos para chamar um programa externo, timeout e sleep e ambos são maneiras perfeitas de alcançar seu objetivo.

timeout O uso de timeout é simples.
Eventualmente, você pode considerar usar também a opção -k para enviar um sinal de eliminação adicional se o primeiro falhar.

timeout 5m YourCommand                                         # 3rd version 

sleep Com sleep você pode usar sua fantasia ou fazer algumas inspirações [ 3 ] . Observe que você pode deixar seu comando em segundo plano ou em primeiro plano (por exemplo, top geralmente precisa estar em primeiro plano).

YourCommand & sleep 5m; kill $!                                # 4th Background
YourCommand & pid=$! ; (sleep 5m; kill $pid;) &                # 5th Background

bash -c '(sleep 5m; kill $$) & exec YourCommand'               # 6th Foreground
(cmdpid=$BASHPID; (sleep 5m; kill $cmdpid) & exec YourCommand) # 7th Foreground

Explicações

  • Na 4 ª versão você executa em background YourCommand então seu shell sleep s por 5 minuites. Quando terminar, o último processo em background ( $! ) será cancelado. Você para sua concha.
  • Na quinta versão, você executa em background YourCommand e armazena imediatamente esse PID na variável $pid . Então você executa em background um nap de 5 minutos e seu comando consequente que matará o PID armazenado. Desde que você enviou este grupo de comandos em segundo plano, você não para o seu shell. Você precisa armazenar o PID em uma variável porque o valor de $! pode ser atualizado por uma eventual execução de outro programa em segundo plano. Em palavras simples, você evita o risco de matar o processo errado ou nenhum processo.
  • Na 6ª versão ele é chamado de novo shell bash que se suicidará em 5 minutos via $$ , então é executado seu comando que permanece em primeiro plano.
  • Na 7ª versão, é invocado um subshell () que armazena seu PID em uma variável ( cmdpid ) e se mata com outro subshell enviado em execução em segundo plano, então executa YourCommand em primeiro plano.

É claro que em cada versão você pode enviar o sinal de kill que você precisa, do padrão para o extremo kill -9 , para ser usado somente quando realmente necessário.

Referências

  • [ 1 ] Os Coreutils
  • [ 2 ] O Guia do Bash Beginners
  • [ 3 ] O BashFAQ
por 25.02.2016 / 19:12
10

Para o seu caso em particular, a maioria das implementações de ping support -c ou --count terminará após um determinado número de pings:

ping -c 300 host.example.com

Para uma solução mais geral, veja as outras respostas.

    
por 25.02.2016 / 12:20
8

Você pode fazer isso com um script simples como este:

#!/bin/bash

#
# $1 is the time to let the program run, and $2, $3, ... are the command itself.
#

"${@:2}" &
PID=$!
sleep "${@:1:1}"
kill -2 $PID

(sinal SIGINT = 2 usado de acordo com a sugestão de Matija Nalis no comentário abaixo).

Uma explicação da expressão bash (incomum?) $@:... : os parâmetros posicionais, ( $*, $@, "$*", "$@" ) admitem a seguinte especificação extra, por exemplo:

"${@:START:COUNT}"

que significa: de todos os parâmetros, tomar COUNT deles, o primeiro a ser tomado na posição START; se COUNT for omitido, leve todos eles até o final, começando com a posição START. Lembre-se que $0 é o nome do programa. Se START for negativo, comece a contar a partir do final e lembre-se de que COUNT não pode ser negativo, portanto, o último argumento é "${@:-1}" . Além disso, apenas sempre inclui os parâmetros posicionais entre aspas duplas.

    
por 25.02.2016 / 07:50
4

Desde que você mencionou ping em seu exemplo; este comando tem algumas opções para parar após um período de tempo específico:

  • w deadline Specify a timeout, in seconds, before ping exits regardless of how many packets have been sent or received. In this case ping does not stop after count packet are sent, it waits either for deadline expire or until count probes are answered or for some error notification from network.
  • W timeout Time to wait for a response, in seconds. The option affects only timeout in absence of any responses, otherwise ping waits for two RTTs.

man ping

    
por 25.02.2016 / 13:51