Pure bash
construído em, sem coreutils
Descobri que esta solução funciona em bash
depender de um built-in comando sem chamar um executável externo. Funciona em sistemas onde, eventualmente, nem sequer são 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ê enviar um comando no fundo com &
, seu PID é armazenado na variável interna $!
(presente na versão moderna dash
, csh
, bash
, tcsh
, zsh
...).
O que realmente faz a diferença entre as conchas é a presença do built-in comando read
[ 2 ] e da opção -t
. Na 1ª versão, se o usuário não concluir uma linha de entrada antes da quantidade especificada de segundos, a instrução será encerrada e um código de retorno de erro será gerado.
-t TIMEOUT Faz com que a leitura atinja o tempo limite e retorne a falha se uma linha completa de entrada não for lida dentro de segundos de TIMEOUT.
A segunda versão funciona como a 1ª, mas você pode abortar o tempo limite final pressionando enter.
De fato, o operador ou ||
executa a kill
instrução somente se o read
comando sair com um código de retorno diferente de zero, como quando o tempo limite expirar. Se você pressionar enterantes 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 tem nenhuma necessidade de economizar o tempo e os recursos para chamar um programa externo, timeout
e sleep
e são ambos excelentes maneiras para alcançar seu objetivo.
timeout
O uso de timeout
é direto.
Eventualmente, você pode considerar usar também a -k
opção de enviar um sinal de interrupção adicional se o primeiro falhar.
timeout 5m YourCommand # 3rd version
sleep
Com sleep
você, você pode usar sua fantasia ou inspirar-se [ 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 quarta versão, você executa em segundo plano
YourCommand
e, em seguida, seu shell sleep
fica por 5 minuites. Quando terminar, o último processo em segundo plano ( $!
) será eliminado. Você para sua concha.
-
Na quinta versão, você executa em segundo plano
YourCommand
e armazena imediatamente esse PID na variável $pid
. Em seguida, você executa em segundo plano uma soneca de 5 minutos e seu consequente comando que mata o PID armazenado. Como você enviou esse grupo de comandos em segundo plano, não interrompe 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 suicida em 5 minutos
$$
, e 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 na execução em segundo plano, depois executa YourCommand em primeiro plano.
É claro que em cada versão você pode enviar o sinal de interrupção necessário, do padrão ao extremo kill -9
, para ser usado apenas quando realmente necessário.
Referências
- [ 1 ] Os Coreutils
- [ 2 ] Guia para iniciantes do Bash
- [ 3 ] O BashFAQ