
Gostaria de agendar um comando para ser executado em um horário específico, identificado por um carimbo de data/hora Unix. Parece que isso pode ser possível com o systemd, usando systemd-run
, mas como isso funcionaria? E o que aconteceria com o comando agendado se a máquina fosse desligada ou suspensa no momento em que o comando fosse agendado?
Pergunta relacionada: fazer a mesma coisa com at
from atd
(requer analisar o carimbo de data/hora em uma data):É possível usar o comando at para agendar a execução de um trabalho em um determinado carimbo de data/hora?
Responder1
systemd-run
pode agendar um comando para ser executado em um horário específico,desde que:
- o sistema não é desligado antes desse horário, porque ele grava um arquivo de serviço e temporizador transitório em /run, que é limpo na reinicialização, e
- o sistema não é suspenso durante esse horário específico, a menos que você use a opção "WakeSystem" (veja abaixo).
Veja ainda mais abaixo uma opção de reinicialização persistente.
Um exemplo simples para systemd-run
:
# generate an arbitrary timestamp, in seconds-since-the-epoch
timestamp=$(date -d 'now + 42 seconds' +%s)
systemd-run --on-calendar "$(date -d @"$timestamp" +'%F %T')" \
--timer-property=AccuracySec=1us \
touch /tmp/done
As partes importantes para systemd-run
usar um carimbo de data/hora segundos desde a época são:
- usar
--on-calendar
e - aqui, usando a data GNU para converter o carimbo de data e hora dos segundos desde a época em um formato
systemd-run
compreensível. Você mesmo pode inserir ou converter o carimbo de data/hora, desde que o resultado esteja em um formatoformato que o OnCalendar entende.
A documentação atual do OnCalendar indica que ele oferece suporte direto à entrada em um carimbo de data/hora segundos desde a época. Esse suporte '@seconds' foi adicionado emversão do sistema 234(pesquise o arquivo nessa página src/basic/calendarspec.c
) emcometer d80e5b7. Sua versão do systemd pode ser anterior a essa alteração; por exemplo:
- RHEL 7 começou com systemd 208 e posteriormente foi atualizado para a versão 219; RHEL 8 usa a versão 239 (referência).
- O Debian 8 usou a versão 215, o Debian 9 usou a versão 232 e o Debian 10 usou a versão 241 (referência).
- Ubuntu 16.04 LTS tinha a versão 229, Ubuntu 17.10 tinha a versão 234 e Ubuntu 18.04 LTS tinha a versão 237 (referência).
Com uma versão suficientemente nova do systemd, você poderia usar esta invocação:
timestamp=$(date -d 'now + 42 seconds' +%s)
systemd-run --on-calendar "@${timestamp}" \
--timer-property=AccuracySec=1us \
touch /tmp/done
Eu também mostrei umpropriedade do temporizador de AccuracySec, cujo padrão é 1 minuto e cujo valor você deve ajustar com base na documentação:
Para otimizar o consumo de energia, certifique-se de definir este valor o mais alto possível e o mais baixo possível.
Eu não testei, mas também há uma opção de timer chamada WakeSystem
que:
fazer com que o sistema retome da suspensão, caso seja suspenso e se o sistema suportar isso. Observe que esta opção apenas garantirá que o sistema seja reiniciado nos horários apropriados, não se encarregará de suspendê-lo novamente após a conclusão de qualquer trabalho a ser realizado.
Você o integraria ao acima assim:
timestamp=$(date -d 'now + 42 seconds' +%s)
systemd-run --on-calendar "$(date -d @"$timestamp" +'%F %T')" \
--timer-property=AccuracySec=1us \
--timer-property=WakeSystem=true \
touch /tmp/done
Para pedir ao systemd para executar um comando em um determinado momento, de uma forma quepersistir além de uma reinicialização, e que é independente de qualquer sessão de login específica, você precisará colocar os arquivos do temporizador e da unidade de serviço em /etc/systemd/system/
./etc/systemd/system é onde a configuração local é armazenadapara o sistema.
Um exemplo de arquivo de temporizador seria:
[Timer]
AccuracySec=1us
[Unit]
Description=2020-01-22 09:50:00 timer
[Timer]
OnCalendar=2020-01-22 09:50:00
e um arquivo de serviço de amostra seria:
[Unit]
Description=my 2020-01-22 09:50:00 service
[Service]
ExecStart=
ExecStart=@/usr/bin/bash "/usr/bin/bash" "-c" "echo 2020-01-22 09:50:00 timer and service ran > /tmp/done"
Você então informaria o systemd sobre os arquivos recarregando-o:
systemctl daemon-reload
... e então habilitando o cronômetro:
systemctl enable foo.timer
... e então iniciando o cronômetro:
systemctl start foo.timer
Você pode querer remover periodicamente o cronômetro expirado e as unidades de serviço de /etc/systemd/system, assim que o tempo tiver passado.