Posso capturar um sinal de relógio no meu script bash?

3

Eu poderia prender um sinal de 5 minutos dentro do meu script? Eu imagino algo assim,

function dosomething {
   echo "It's been 5 minutes."
}

trap dosomething SIGNAL-EVERY-5-MINUTES

while true
do
    sleep 10
done

Note que este exemplo não tem sentido. É só perguntar se é possível prender algo a cada x tempo.

EDITAR: Com base na resposta @ vinc17, notei que o comando sleep do shell principal não é interrompido por USR1 signal, e é isso que eu quero fazer.

#!/bin/bash
time=10

(
  set -e
  while true
  do
    sleep 30
    # Since this is run as a subshell (instead of an external command),
    # the parent pid is $$, not $PPID.
    kill -USR1 $$
  done
) &

finish() {
   kill $!
   echo "Closing."
   exit 0
}

changetime() {
   echo "Signal USR1 received."
   time=$(( $RANDOM % 8 + 1))
}

trap changetime USR1
trap finish SIGINT

while true
do
  echo "before sleep"
  sleep $time
  echo "after sleep"
done

saídas,

before sleep
Signal USR1 received.
after sleep
before sleep
Signal USR1 received.
after sleep
before sleep
Signal USR1 received.
Closing.

EDIT2: Eu editei o exemplo acima, resultando na mesma saída, mas adiciona mais uma dificuldade: O tempo de suspensão é alterado pela função USR1 trap. Então, agora, a cada 30 segundos, um tempo aleatório entre 1 e 8 é escolhido. Então, eu preciso matar sleep do script principal quando o sinal muda seu tempo. Insisto em que não faz sentido, mas preciso saber se é possível.

    
por whitenoisedb 18.09.2014 / 00:55

2 respostas

5

Você pode executar um processo que enviará um sinal (por exemplo, SIGALRM ) para o script de shell a cada x tempo e usará uma interceptação para esse sinal. Esse processo pode ser um script fazendo algo como:

set -e
while true
do
  sleep 300
  kill -ALRM $PPID
done

se iniciado pelo script de shell principal.

O script de shell principal deve eliminar esse processo quando não for mais necessário, e / ou o processo deve terminar quando o pid não existir mais (no entanto, há uma condição de corrida sobre isso).

Nota: se o script de shell principal usar o comando sleep , ele interagirá com o sinal ALRM , mas você poderá usar SIGUSR1 ou SIGUSR2 .

Aqui está um exemplo usando um subshell. Para tornar o comportamento mais fácil de ver, substituí o período de 5 minutos ( sleep 300 ) por um período de 5 segundos ( sleep 5 ).

#!/bin/sh

{
  set -e
  while true
  do
    sleep 5
    # Since this is run as a subshell (instead of an external command),
    # the parent pid is $$, not $PPID.
    kill -USR1 $$
  done
} &

trap 'echo "Signal USR1 received."' USR1

while true
do
  date
  sleep 1
done

O script pode ser interrompido com Ctrl-C. Ele não mata o subshell quando isso acontece, mas se o pid não for reutilizado, o subshell terminará automaticamente depois de não mais do que o período (aqui, 5 segundos) porque o comando kill falha ( kill: No such process ). / p>     

por 18.09.2014 / 01:10
2

Sim. A maneira mais fácil é fazer exatamente o que você descreve originalmente na sua pergunta. É só que parte do algo que você deveria estar gerando outro processo filho para enviar um sinal ao seu processo 5 minutos no futuro. Pegando uma página do livro de @ vinc17, vou encurtar o intervalo para 5 segundos também.

trap 'ME=$$
     : $( (sleep 5
     ps -p $ME >/dev/null 2>&1 && { 
        echo hey >/dev/tty
        kill -USR1 $ME
     })&)
' USR1; kill -USR1 $$

Dessa forma, você não tem um processo de longa duração apenas pedindo para ser zumbi. Em vez disso, você tem um novo contador de propósito único que obtém uma nova referência ao PID do pai em cada intervalo. Eu também incorporo um pequeno teste apenas para garantir que a criança não tente fazer seu único trabalho caso seu pai tenha morrido desde que se separou.

Execute isso e a cada 5 segundos você deve obter:

hey
hey
hey
hey
hey
hey
hey
hey
hey
hey

Este exemplo também irá travar o terminal enquanto isso, senão ele não fará nada se você tentar entender todo o processo. Isto é devido a sua espera em /dev/tty - escolha um arquivo em vez disso, se você quer dizer executar tudo em segundo plano, senão faça uma chamada stty direta e reexecute o tty quando quiser.

    
por 18.09.2014 / 09:08

Tags