Configurar um cronjob no Linux: agendamento, permissões e os erros mais comuns
A tarefa corre na shell, mas não no cron. Este guia explica os cinco campos de tempo, a diferença entre a crontab de utilizador e /etc/cron.d, a armadilha do PATH e como comprovar que um cronjob correu mesmo.
Um cronjob configura-se em cinco minutos e costuma custar horas depois. O comando funciona sem problemas na shell, a partir do cron não acontece nada e, no log, lê-se na melhor das hipóteses que o cron arrancou qualquer coisa. Este artigo trata exatamente dos pontos onde os guias habituais terminam: as mensagens de erro reais, as diferenças entre as distribuições e a questão de saber como reconhecer que uma tarefa correu mesmo até ao fim e não apenas arrancou.
Todas as indicações referem-se a Debian 13 (trixie), Debian 12 (bookworm), Ubuntu 24.04 LTS e Ubuntu 22.04 LTS. Estes quatro sistemas usam o mesmo cron (a variante Debian do Vixie Cron) e não o cronie do Red Hat e do Fedora. Esta diferença é decisiva mais à frente, no capítulo do fuso horário.
O serviço cron está sequer a correr?
Em instalações completas, o cron está presente. Em imagens cloud mínimas, em imagens base de container e em instalações netinst reduzidas, o pacote falta com frequência. Esta é a primeira questão a esclarecer antes de começar a depurar seja o que for.
command -v crontab
systemctl status cron
É de propósito command -v crontab e não command -v cron: o próprio serviço encontra-se em /usr/sbin e, no Debian, esse diretório só faz parte do caminho de pesquisa do root. Como utilizador normal, simplesmente não obtém qualquer resultado, apesar de o cron estar instalado. No Ubuntu 24.04, a consulta funciona também com um utilizador sem privilégios. Já o crontab está em /usr/bin em todos os sistemas e é, por isso, visível para toda a gente, e systemctl status cron responde de qualquer forma à pergunta mais importante, ou seja, se o serviço está mesmo a correr.
Se o serviço não existir, instale-o:
apt-get update
apt-get install -y cron
systemctl enable --now cron
No Debian e no Ubuntu, o serviço chama-se cron e não crond. Quem está habituado ao Red Hat recebe aqui um Unit crond.service could not be found. e procura no sítio errado.
Em funcionamento normal não é preciso reiniciar nada: o cron do Debian vigia os diretórios das crontabs através de inotify e lê as alterações sozinho. Depois de editar uma crontab, não tem portanto de reiniciar o serviço. As exceções são a mudança do fuso horário do sistema e alterações em /etc/default/cron.
Os cinco campos, e a armadilha do quinto
Cada linha começa com cinco campos de tempo, seguidos do comando.
| Campo | Intervalo | Observação |
| Minuto | 0 a 59 | |
| Hora | 0 a 23 | formato de 24 horas, sem fuso horário |
| Dia do mês | 1 a 31 | |
| Mês | 1 a 12 | também jan a dec |
| Dia da semana | 0 a 7 | 0 e 7 são ambos domingo, também sun a sat |
30 4 * * * /usr/local/bin/backup.sh # diariamente às 04:30
*/10 * * * * /usr/local/bin/check.sh # a cada 10 minutos
0 2 * * 0 /usr/local/bin/weekly.sh # aos domingos às 02:00
15 3 1 * * /usr/local/bin/monthly.sh # no dia 1 às 03:15
0 9-17 * * 1-5 /usr/local/bin/business.sh # de hora a hora em dias úteis, das 9 às 17
Há dois pormenores que quase toda a gente interpreta mal.
O dia do mês e o dia da semana formam um OU, não um E. Assim que ambos os campos estão restringidos, ou seja, nenhum deles contém um asterisco, a tarefa corre quando um dos dois corresponde. 0 3 13 * 5 não significa "sexta-feira, dia 13", mas sim "todos os dias 13 e, além disso, todas as sextas-feiras". Se quiser mesmo sexta-feira dia 13, verifique isso dentro do próprio script.
Os passos não dividem o intervalo de forma uniforme. */7 * * * * corre aos minutos 0, 7, 14, 21, 28, 35, 42, 49 e 56, e depois o contador salta para a hora seguinte. Entre o minuto 56 e o minuto 0 passam, portanto, apenas quatro minutos. Isto vale para qualquer intervalo que não divida 60 (ou 24) de forma exata. Para "a cada 90 minutos" não existe uma notação limpa no cron, e aqui um timer do systemd é a melhor escolha.
Utilizar corretamente o crontab -e
A crontab de utilizador nunca deve ser editada diretamente em /var/spool/cron/crontabs/, mas sempre através da ferramenta própria:
crontab -e
Na primeira invocação, o programa responde com no crontab for root - using an empty one. Em sistemas acabados de instalar, segue-se depois uma escolha de editor. Se não existir editor nenhum, por exemplo numa imagem reduzida, a chamada aborta com uma mensagem do género /usr/bin/sensible-editor: 25: editor: not found. Solução: instalar um editor ou definir explicitamente o editor pretendido.
apt-get install -y nano
EDITOR=nano crontab -e
A grande vantagem de crontab -e face à escrita direta do ficheiro é a validação no momento de gravar. Se uma linha estiver mal formada, vê o seguinte:
"/tmp/crontab.7hK2mn/crontab":3: bad minute
errors in crontab file, can't install.
Do you want to retry the same edit? (y/n)
O número da linha está correto, o campo indicado na mensagem nem sempre: bad minute aparece também quando falta simplesmente um campo, porque o parser passa então a ler tudo deslocado para a esquerda. Em caso de sucesso, o processo termina com crontab: installing new crontab. Só esta linha significa que a alteração foi aceite.
Outros comandos que deve conhecer:
crontab -l # mostrar
crontab -l > /root/crontab.bak # guardar cópia
crontab -u www-data -l # ler a crontab de outro utilizador (como root)
crontab -i -r # apagar, com confirmação (apenas no terminal)
Uma nota sobre a cópia de segurança: crontab -l > /root/crontab.bak devolve no crontab for root e o código de saída 1 enquanto não existir qualquer crontab para o utilizador. Mesmo assim, o ficheiro de destino é criado, nesse caso com 0 bytes. Pela ordem deste artigo isso não se nota, mas nota-se muito bem num script que verifique o código de saída ou que sobrescreva um backup mais antigo.
crontab -r sem -i apaga a crontab completa de imediato e sem qualquer pergunta. Como r e e ficam próximas no teclado, este é um caso real de perda de dados. No terminal, habitue-se por isso a crontab -i -r e guarde antes uma cópia com crontab -l.
A palavra decisiva aqui é terminal. crontab -i -r é um comando puramente interativo. Se a entrada padrão não estiver ligada a um terminal, ou seja, num script, num cronjob ou numa linha única como ssh host "crontab -i -r", a confirmação entra num ciclo sem fim: crontab: really delete root's crontab? (y/n) Please enter Y or N: Please enter Y or N: ... repete-se sem limite e escreve centenas de kilobytes de saída em segundos, e a chamada só termina com uma interrupção vinda de fora. Para tudo o que for automatizado, use por isso a variante não interativa e guarde antes uma cópia:
crontab -l > /root/crontab.bak # guardar antes de apagar
crontab -r # apagar, sem confirmação
printf "y\n" | crontab -i -r # manter a pergunta, dar a resposta
Se existirem /etc/cron.allow ou /etc/cron.deny, são esses ficheiros que decidem quem pode sequer criar crontabs. Os utilizadores afetados recebem: You (username) are not allowed to use this program (crontab). Se /etc/cron.allow existir, vale em exclusivo e todos os utilizadores não listados ficam bloqueados.
Crontab de utilizador, /etc/crontab e /etc/cron.d
Existem quatro sítios onde os agendamentos podem estar e todos têm formatos diferentes. É exatamente aqui que nascem os erros mais difíceis de encontrar.
Crontab de utilizador: cinco campos
É mantida através de crontab -e, corre com o utilizador a que pertence e não tem campo de utilizador. Se mesmo assim escrever um, o cron tenta executar o nome de utilizador como comando e encontra no e-mail ou no log:
/bin/sh: 1: root: not found
/etc/cron.d: seis campos
Os ficheiros em /etc/cron.d/ são crontabs de sistema e têm um campo de utilizador entre os campos de tempo e o comando. Este é o sítio certo para tarefas que pertencem a uma aplicação ou a uma gestão de configuração, porque cada ficheiro pode ser substituído individualmente.
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=""
0 3 * * * root /usr/local/bin/backup.sh >> /var/log/kh-backup.log 2>&1
Se se esquecer do campo de utilizador, o cron interpreta a primeira palavra do comando como nome de utilizador e a linha falha em silêncio, porque esse utilizador não existe.
Há três regras para /etc/cron.d/ que são violadas com regularidade:
- O nome do ficheiro não pode conter um ponto. São permitidos apenas letras, algarismos, sublinhados e hífenes.
backup.cronoukh-backup.shsão ignorados sem qualquer aviso. A razão está na gestão de pacotes: assim, restos como.dpkg-distou.dpkg-oldnunca são executados. Chame ao ficheiro simplesmentekh-backup. - As permissões e o proprietário têm de estar corretos. São esperados
root:roote o modo 0644. Caso contrário, aparecem no log mensagens como(*system*) WRONG FILE OWNER,(*system*) BAD FILE MODEou um aviso sobre um modo inseguro, com permissão de escrita para o grupo ou para outros. Nesse caso, a tarefa não corre. - O ficheiro tem de terminar com uma quebra de linha. O cron exige que cada entrada termine com um newline. Se a última linha não tiver quebra, é simplesmente ignorada, e sem qualquer aviso: num teste comparativo com um ficheiro em tudo idêntico, mas sem quebra final, a tarefa não correu uma única vez, sem mensagem de erro e sem linha de log. Quem gera o ficheiro com
echo -n, com umprintfsem\nfinal ou a partir de um template sem linha vazia no fim perde exatamente a última tarefa.
chown root:root /etc/cron.d/kh-backup
chmod 0644 /etc/cron.d/kh-backup
/etc/crontab e os diretórios cron.*
/etc/crontab tem igualmente seis campos e pertence à distribuição. Altere-o apenas se souber porquê. Através de run-parts, chama os diretórios /etc/cron.hourly, cron.daily, cron.weekly e cron.monthly. Os scripts colocados aí precisam do bit de execução e também não podem ter um ponto no nome. Um backup.sh em /etc/cron.daily/ nunca é executado, um backup sim. Pode testar isso sem executar nada:
run-parts --test /etc/cron.daily
São listados apenas os scripts que o run-parts arrancaria de facto. Se o seu não aparecer na lista, o problema está no nome ou no bit de execução.
Porque é que o PATH no cron é diferente
Esta é, de longe, a causa mais frequente do "funciona na shell, mas não no cron". O cron não arranca uma shell de login. Nem ~/.bashrc, nem ~/.profile, nem /etc/profile são lidos. Para as crontabs de utilizador, o cron do Debian define um caminho de pesquisa mínimo:
PATH=/usr/bin:/bin
Faltam assim /usr/local/bin e /usr/sbin. No Debian 12, no Debian 13, no Ubuntu 22.04 e no Ubuntu 24.04, /usr/bin e /usr/sbin continuam a ser diretórios separados, porque o usr-merge afeta apenas /bin e /sbin. Tudo o que colocou por sua conta em /usr/local/bin, tudo o que vem de pip install, tudo o que vem de um Node instalado via nvm e ferramentas de sistema como ufw ou iptables simplesmente não existem para o cron. A mensagem de erro é então:
/bin/sh: 1: backup.sh: not found
A segunda parte da armadilha: o cron define SHELL=/bin/sh. No Debian e no Ubuntu, /bin/sh é uma ligação simbólica para o dash e não para o bash. Qualquer expressão típica de bash no cabeçalho do script ou diretamente na linha da crontab falha:
/bin/sh: 1: [[: not found
/bin/sh: 1: source: not found
/bin/sh: 1: Syntax error: "(" unexpected
Três contramedidas, por esta ordem:
- Usar caminhos absolutos.
/usr/local/bin/backup.shem vez debackup.sh,/usr/bin/phpem vez dephp. Esta é a variante mais robusta, porque funciona independentemente de qualquer variável de ambiente. Consulte o caminho em vez de o escrever de cabeça:command -v datedevolve/usr/bin/dateno Debian 13, no Debian 12, no Ubuntu 24.04 e no Ubuntu 22.04, mas/bin/dateem sistemas mais antigos como o Debian 11. Uma linha com um caminho errado é aceite pelo crontab sem comentários e sem aviso, falhando só em tempo de execução e, mesmo aí, em silêncio. Para controlar, use uma vezcrontab -le uma vezenv -i /bin/sh -c "/usr/bin/date", que assinala de imediato um caminho errado comnot found. - Definir PATH e SHELL no início da crontab. As atribuições valem para todas as linhas seguintes. Importante: o cron não expande variáveis,
PATH=$PATH:/opt/binnão funciona, escreva o caminho por extenso. - Utilizar um script wrapper. A linha da crontab chama apenas o script e o script define o seu próprio ambiente.
#!/bin/bash
set -euo pipefail
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
cd /srv/app
exec ./do-the-work.sh
Se quiser saber o que o cron entrega realmente à sua tarefa, peça-lhe que o mostre. Adicione durante um minuto:
* * * * * /usr/bin/env > /tmp/cron-env.txt 2>&1
Só por esta via se vê o ambiente que o cron define de facto. Uma shell recriada com env -i chega apenas perto, porque traz consigo o seu próprio caminho predefinido. Depois compare /tmp/cron-env.txt com o seu ambiente interativo. Normalmente saltam à vista não só PATH e SHELL, mas também as variáveis de locale em falta. Sem LANG, tudo corre no locale C, o que altera ordens de ordenação, formatos de data e a apresentação de caracteres acentuados. Scripts que contam com LANG=de_DE.UTF-8 comportam-se de outra forma no cron. Também o ssh-agent falta, razão pela qual as tarefas com acesso SSH precisam de uma chave sem palavra-passe e de um -i explícito.
A última pequena maldade desta categoria: o sinal de percentagem. Numa linha de crontab, um % não escapado é convertido numa quebra de linha e tudo o que vem a seguir é entregue ao comando como entrada padrão. Os formatos de data têm portanto de ser escapados.
0 2 * * * /usr/bin/tar -czf /backup/web-$(date +\%F).tar.gz /var/www
Redirecionar a saída, e-mails e "No MTA installed"
Por predefinição, o cron envia por e-mail ao dono da crontab tudo o que uma tarefa escreve em stdout ou stderr. Num servidor sem sistema de e-mail, isso acaba no log:
(CRON) info (No MTA installed, discarding output)
Isto não é um erro da tarefa. Significa apenas que houve saída e que ninguém a pôde receber. Uma tarefa silenciosa não produz esta linha. Por isso, ela é até um sinal útil: se aparecer de repente, é porque a sua tarefa começou a escrever alguma coisa, normalmente uma mensagem de erro.
Para o redirecionamento existem três padrões úteis:
# tudo para um ficheiro de log, incluindo os erros
0 3 * * * /usr/local/bin/backup.sh >> /var/log/kh-backup.log 2>&1
# saída normal descartada, erros continuam a seguir por e-mail
0 3 * * * /usr/local/bin/backup.sh > /dev/null
# tudo para o journal, devidamente identificado
0 3 * * * /usr/local/bin/backup.sh 2>&1 | /usr/bin/logger -t kh-backup
A variante > /dev/null 2>&1 é popular e perigosa: descarta também todas as mensagens de erro. Uma tarefa que falha há quatro meses fica exatamente igual a uma que corre bem. Se quiser prescindir dos e-mails, prefira MAILTO="" no início da crontab e escreva a saída para um ficheiro. Se quiser e-mails para um endereço específico, defina MAILTO=alerts@example.org, mas para isso precisa de um sistema de e-mail instalado.
Os ficheiros de log próprios em /var/log/ crescem sem limite. Crie para eles uma pequena regra em /etc/logrotate.d/, caso contrário o cronjob mais bem-sucedido acaba por encher o disco.
Como reconhecer que a tarefa correu mesmo
É aqui que o guia rápido se separa da verificação sólida. O cron regista o arranque de uma tarefa. Não regista nem o fim nem o código de saída. Uma linha CMD no log prova apenas que o cron arrancou a shell, não que o seu script terminou com sucesso.
Os logs leem-se de forma diferente consoante o sistema:
journalctl -u cron --since "30 min ago"
journalctl -t CRON --since today
No Debian 12 e no Debian 13 este é o único caminho, porque desde o bookworm o rsyslog já não é instalado por predefinição. Um ficheiro /var/log/syslog normalmente já não existe nesses sistemas. Quem o procura e não o encontra conclui erradamente que a tarefa não arrancou.
No Ubuntu 22.04 e 24.04, o rsyslog está normalmente presente e aí funciona também:
grep CRON /var/log/syslog
Um ficheiro próprio /var/log/cron.log não existe de origem em nenhuma das quatro versões. A regra correspondente em /etc/rsyslog.d/50-default.conf está comentada. Não procure por esse ficheiro, ele só existe se alguém o tiver ativado.
Uma prova limpa vem, por isso, da própria tarefa. Faça o script escrever no fim uma marca temporal e o código de saída:
#!/bin/bash
set -euo pipefail
trap 'echo "$(date -Is) kh-backup terminado, exit $?" >> /var/log/kh-backup.log' EXIT
# o trabalho propriamente dito
Assim passa a ter três provas em vez de uma: a linha CRON no journal (o cron arrancou), a linha final no seu ficheiro de log (o script chegou ao fim) e o código de saída (terminou de forma limpa). Só quando as três batem certo é que a tarefa funciona.
Se uma tarefa puder demorar mais do que o seu intervalo, proteja-a ainda contra sobreposições. Caso contrário, um dia arrancam dez instâncias em paralelo e acabam por derrubar o servidor:
*/5 * * * * /usr/bin/flock -n /var/lock/kh-sync.lock /usr/local/bin/sync.sh
flock -n termina de imediato se já existir uma instância em execução. A ferramenta faz parte de util-linux e está presente nos quatro sistemas.
@reboot e porque o systemd costuma ser melhor
Com @reboot é possível executar um comando no arranque. Existem além disso @daily, @hourly, @weekly, @monthly e @yearly, que substituem os cinco campos de tempo.
@reboot /usr/local/bin/start-app.sh
Isto parece cómodo e tem três fraquezas sérias:
- O momento não é "depois do arranque do sistema", mas sim "quando o cron arranca". Saber se a rede, a base de dados ou um mount já estão prontos nessa altura é pura questão de sorte. O remendo habitual é um
sleep 30antes, o que apenas adia o problema. - Um reinício do serviço cron volta a disparar o @reboot. Um
systemctl restart cron, por exemplo depois de uma atualização de pacotes, arranca a sua aplicação uma segunda vez, apesar de a primeira ainda estar a correr. - Não existe qualquer monitorização. Sem código de saída, sem reinício em caso de falha, sem estado.
Para tudo o que deve correr de forma permanente, o que faz falta é um serviço systemd, não um cronjob. Para tarefas recorrentes, um timer é a melhor escolha. Bastam dois ficheiros:
[Unit]
Description=KernelHost Backup
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
[Unit]
Description=KernelHost Backup diário
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
RandomizedDelaySec=900
[Install]
WantedBy=timers.target
O que se ativa é o timer, não o serviço:
systemctl daemon-reload
systemctl enable --now kh-backup.timer
systemctl list-timers kh-backup.timer
As três vantagens decisivas face ao cron: Persistent=true recupera uma execução perdida no arranque seguinte, enquanto o cron a salta sem dizer nada. O código de saída aparece em systemctl status kh-backup.service, ou seja, vê sem qualquer registo próprio se correu bem. E a saída completa fica disponível com journalctl -u kh-backup.service, sem redirecionamento e sem e-mail. Já agora, o caminho de pesquisa do systemd é mais generoso do que o do cron e inclui por predefinição também /usr/local/bin, mas, sem nada de seu, continua mesmo assim a ser curto.
Para tarefas de arranque, substitua @reboot por um serviço com dependências claras:
[Unit]
After=network-online.target
Wants=network-online.target
Assim, a sua tarefa só corre, com garantia, quando a rede estiver mesmo disponível. Mais sobre units e a sua estrutura encontra em criar um serviço systemd.
Fuso horário, UTC e a hora de verão
O cron calcula sempre com o fuso horário do sistema, definido em /etc/localtime. Em muitos servidores e em quase todas as imagens cloud, esse fuso é UTC. Uma tarefa marcada para 0 3 * * * corre então, no verão, às 05:00 da hora de verão da Europa Central e não às 03:00. Verifique primeiro com o que está a lidar:
readlink -f /etc/localtime
timedatectl show -p Timezone --value
date
date -u
readlink -f /etc/localtime indica o caminho em /usr/share/zoneinfo e, com ele, o fuso realmente em vigor, por exemplo /usr/share/zoneinfo/Etc/UTC ou /usr/share/zoneinfo/Europe/Vienna. Funciona nas quatro versões e também onde o systemd não corre. timedatectl show -p Timezone --value devolve a mesma informação de forma curta e legível por máquina, mas exige systemd.
O hábito que deve abandonar é o de espreitar o /etc/timezone. O Debian 13 já não fornece este ficheiro, um cat /etc/timezone termina aí com cat: /etc/timezone: No such file or directory, e nem sequer a instalação de tzdata o traz de volta. No Debian 12, no Ubuntu 24.04 e no Ubuntu 22.04 ainda existe, ou seja, a resposta varia consoante a versão. Determinante é, em qualquer caso, apenas a ligação simbólica /etc/localtime: um valor escrito à mão em /etc/timezone não altera nada no fuso horário do sistema e, por isso, também não altera nada no momento de disparo das suas tarefas.
Pode mudar o fuso horário do sistema a qualquer momento e, depois disso, convém reiniciar o cron para que o serviço assuma a alteração com segurança:
timedatectl set-timezone Europe/Vienna
systemctl restart cron
Em sistemas sem systemd em execução, defina antes a ligação simbólica diretamente, porque o resultado é o mesmo e pode ser confirmado logo a seguir com readlink -f /etc/localtime:
ln -sf /usr/share/zoneinfo/Europe/Vienna /etc/localtime
Agora o ponto que está errado em muitos guias: o cron do Debian e do Ubuntu não conhece a variável CRON_TZ. Esta variável vem do cronie, o cron do Red Hat, do Fedora e do AlmaLinux. No Debian 13, no Debian 12, no Ubuntu 24.04 e no Ubuntu 22.04 não existe fuso horário por utilizador nem por crontab. Se colocar lá TZ=Europe/Vienna, isso atua exclusivamente sobre o ambiente dos comandos executados, ou seja, um date dentro do script mostra a hora de Viena. O momento do disparo em si fica completamente inalterado e continua a seguir o fuso horário do sistema. Quem não repara nisto fica com uma tarefa aparentemente bem configurada que, ainda assim, corre duas horas ao lado.
Restam três caminhos limpos: definir o fuso horário do sistema em conformidade, converter as horas para UTC ou passar para um timer do systemd, que aceita um fuso horário diretamente no agendamento. Isto pode ser verificado sem qualquer risco:
systemd-analyze calendar "Mon..Fri 03:00 Europe/Vienna"
A saída indica o próximo disparo como uma data concreta. Este é o controlo mais fiável que pode fazer antes de ativar.
Sobre a hora de verão, ainda um conselho prático: não agende tarefas entre as 02:00 e as 03:00. Em março esta hora não existe, em outubro existe duas vezes. Consoante a tarefa, isso significa uma execução perdida ou uma execução a dobrar, ambas uma vez por ano e ambas difíceis de reproduzir. 01:30 ou 03:30 são alternativas discretas. Nos timers do systemd, Persistent=true ajuda ainda a recuperar uma execução perdida.
Diagnóstico rápido em sete passos
Quando um cronjob não corre, percorra esta lista pela ordem indicada. Ela cobre praticamente todos os casos.
- O serviço está a correr?
systemctl status cron. Sem serviço, não há tarefa. - A entrada chegou mesmo lá?
crontab -lpara tarefas de utilizador, caso contrário consulte o ficheiro em/etc/cron.d/. Verifique o nome sem ponto, o modo 0644, o proprietário root e a quebra de linha final. - O cron chegou a arrancá-la?
journalctl -t CRON --since today. Se a linha CMD não aparecer, o problema está no agendamento ou no ficheiro, não no script. - O número de campos está certo? Cinco campos na crontab de utilizador, seis em
/etc/cron.de/etc/crontab. - Caminhos absolutos? Indique cada comando e cada script com o caminho completo e determine esse caminho antes com
command -v, em vez de o escrever à mão. - Ambiente verificado? Adicione uma vez
* * * * * /usr/bin/env > /tmp/cron-env.txt 2>&1, espere um minuto e compare. - Testar no contexto do cron. Não execute o script na sua shell, mas com um ambiente vazio:
env -i PATH=/usr/bin:/bin /bin/sh -c '/usr/local/bin/backup.sh'. O caminho de pesquisa é indicado de propósito.env -i /bin/shsozinho esvazia de facto o ambiente, mas o dash define depois o seu próprio caminho predefinido/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin, que é mais generoso do que o do cron. Precisamente os erros de que aqui se trata continuariam por descobrir. Se a chamada falhar, encontrou a causa, sem ter de esperar pelo próximo momento de disparo.
O último ponto é o mais valioso. Quase todos os cronjobs que "inexplicavelmente" não funcionam falham de forma reproduzível assim que são arrancados com um ambiente vazio. Um enigma que só se manifesta de 24 em 24 horas transforma-se assim num erro que pode corrigir em dez segundos.
Quem faz backups regulares através de cronjob deve também proteger o sistema de destino. Encontra as indicações adequadas no nosso artigo sobre a proteção de um servidor Linux.
Perguntas frequentes
Porque é que o meu script funciona na shell, mas não como cronjob?
O que significa a mensagem No MTA installed, discarding output?
O Debian ou o Ubuntu suportam a variável CRON_TZ?
Porque é que o meu ficheiro em /etc/cron.d é ignorado?
Onde encontro os logs do cron no Debian 12 e 13?
Uma linha CMD no log prova que a tarefa correu com sucesso?
Devo usar @reboot ou um serviço systemd?
2026 KernelHost GmbH. Todos os direitos reservados. Este guia está protegido por direitos de autor. A sua republicação noutros sites, na íntegra, em parte ou de forma editada, não é permitida sem o nosso consentimento por escrito. Citações com indicação da fonte e ligação são expressamente bem-vindas.

