Resumo
O código correto deve ser:
#!/bin/sh
[ "$#" -eq 0 ] && echo "Usage: $0 command [args]" && exit 1
[ "$(date -d tomorrow +'%d')" = 01 ] || exit 0
exec "$@"
Chame esse script end_of_month.sh
e a chamada no cron é simplesmente:
00 12 28-31 * * /path/to/script/end_of_month.sh command
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:
- Faltando um fechamento
fi
.
- Precisa de espaço entre
[
e o seguinte `
.
- É altamente recomendável usar $ (…) em vez de
`…`
.
- É importante que você use aspas em expansões como
"$(…)"
- Há um adicional
;
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 aceita tomorrow
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):
#!/bin/sh
[ "$#" -eq 0 ] && echo "Usage: $0 command [args]" && exit 1
[ "$(date -d tomorrow +'%d')" = 01 ] || exit 0
exec "$@"
Chame esse script end_of_month.sh
e a chamada no cron é simplesmente:
00 12 28-31 * * /path/to/script/end_of_month.sh command
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:
- Cron divide a linha de comando em qualquer um,
%
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:
$ faketime 2018/10/31 ./end_of_month echo "Command will be executed...."
Command will be executed....