Li uma instrução para agendar um script no último dia do mês:
Nota:
O leitor astuto pode estar se perguntando como seria possível definir um comando para executar no último dia de cada mês, porque não é possível definir o valor de um dia para cobrir todos os meses. Esse problema afetou os programadores do Linux e Unix e gerou várias soluções diferentes. Um método comum é adicionar uma instrução if-then que usa o comando date para verificar se a data de amanhã é 01:00 12 * * * if [`date +%d -d tomorrow` = 01 ] ; then ; command1
Isso verifica todos os dias às 12 horas para ver se é o último dia do mês e, nesse caso, o cron executa o comando.
Como [`date +%d -d tomorrow` = 01 ]
funciona?
É correto afirmar then; command1
?
shell-script
cron
date
test
Cálculo
fonte
fonte
; endif
?[
e nãofi
no final. Além disso,%
é especial em crontabs.Respostas:
Resumo
O código correto deve ser:
Chame esse script
end_of_month.sh
e a chamada no cron é simplesmente:Isso executaria o script
end_of_month
(que internamente verificará se o dia é o último dia do mês) apenas nos dias 28, 29, 30 e 31. Não há necessidade de verificar o final do mês em nenhum outro dia.Post antigo.
Essa é uma citação do livro "Linux Command Line and Shell Scripting Bible" de Richard Blum, Christine Bresnahan, pp. 442, terceira edição, John Wiley & Sons © 2015.
Sim, é o que diz, mas está errado / incompleto:
fi
.[
e o seguinte`
.`…`
."$(…)"
;
apósthen
Como eu sei? (bem, por experiência), mas você pode tentar o Shellcheck . Cole o código do livro (após os asteriscos) e ele mostrará os erros listados acima, além de um "erro de digitação". Um script sem erros no Shellcheck é o seguinte:
#!/bin/sh if [ "$(date +%d -d tomorrow)" = 01 ] ; then script.sh; fi
Esse site funciona porque o que foi escrito é "código shell". Essa é uma sintaxe que funciona em muitos shells.
Alguns problemas que o shellcheck não menciona são:
Supõe-se que o comando date seja a versão da data GNU. Aquele com uma
-d
opção que aceitatomorrow
como valor (busybox tem uma opção -d, mas não entende o amanhã e o BSD tem uma-d
opção, mas não está relacionado à "exibição" de tempo).É melhor definir o formato depois de todas as opções
date -d tomorrow +'%d'
.O horário de início do cron é sempre no horário local, o que pode fazer com que um trabalho seja iniciado 1 hora antes ou depois da contagem exata do dia, se o horário de verão estiver definido ou não.
O que fizemos foi um script de shell que poderia ser chamado com cron. Podemos modificar ainda mais o script para aceitar argumentos do programa ou comando para executar, assim (finalmente, o código correto):
Chame esse script
end_of_month.sh
e a chamada no cron é simplesmente:Isso executaria o script
end_of_month
(que internamente verificará se o dia é o último dia do mês) apenas nos dias 28, 29, 30 e 31. Não há necessidade de verificar o final do mês em nenhum outro dia.Verifique se o caminho correto está incluído. O PATH dentro do cron não será (provavelmente) o mesmo que o PATH do usuário.
Observe que há um script de final de mês testado (como indicado abaixo) que poderia chamar muitos outros utilitários ou scripts.
Isso também evitará o problema adicional que o cron gera com a linha de comando completa:
%
mesmo que citado por'
ou"
(apenas um\
funciona aqui). Essa é uma maneira comum pela qual os trabalhos cron falham.Você pode testar se o
end_of_month.sh
script funciona corretamente em alguma data (sem esperar até o final do mês para descobrir que não funciona) testando-o com tempo de folga:fonte
date
(ou odate
built-in do ksh93 se o ksh93 foi construído como parte do ast-open) suportadate -d tomorrow +%s
oudate +%s tomorrow
).* * * * * echo "$(date -u +'date %c')" >>~/testfile
não funciona porque se esqueceu de citar o\%
(que se torna difícil de depurar se apenas uma tentativa por mês for possível). @KusalanandaSupondo que os erros de sintaxe sejam corrigidos e o comando reformulado levemente para ser menos detalhado:
Isso é executado
date +%d -d tomorrow
(supondo quedate
seja usado o GNU ) para obter a data de amanhã como um número de dois dígitos. Se o número não for01
, hoje não é o último dia do mês. Nesse caso, os testes bem-sucedido ecommand1
é não executado. O trabalho é executado ao meio-dia nos dias que podem ser o último dia do mês.O comando original:
Isso tem alguns problemas:
[
.;
diretamente depoisthen
.%
é especial nas especificações de tarefas do cron e deve ser escapado como\%
(consulteman 5 crontab
).fi
no final que combine com oif
.fonte
[ ... ] && command1
vez deif...
é que, nos dias que não são o último dia do mês, o trabalho cron termina com um status de saída diferente de zero e essa falha pode ter que ser relatada. Usar[ "$(...)" != 01 ] || command1
é outra maneira de evitar o problema.;
entrethen
ecommand1
."
ou'
(exceto\
), o sinal de porcentagem%
vai fazer cron quebrar a linha em duas partes. Essa é uma maneira usual de fazer com que o cron falhe.Para agendar o último dia de cada mês, você pode tentar:
0 0 15,L * *
.fonte