La lliçó anterior va acabar amb un diagnòstic i una tasca pendent: la còpia de seguretat nocturna de Tramontana s'executa a l'hora equivocada, amb la prioritat equivocada i sobre més dades de les necessàries. Algú la va programar en algun moment i ningú no hi ha tornat a mirar. És el retrat exacte de l'automatització mal feta: funciona fins que un dia tira el servei a terra.

cron és el temporitzador d'Unix. Porta funcionant des del 1975 i continua sent la manera més estesa de dir a un servidor «fes això cada dia a les quatre». La seva sintaxi és breu i les seves fallades són sempre les mateixes tres, repetides a totes les empreses del món. Aquesta lliçó et dona la sintaxi completa i, sobretot, aquestes tres fallades amb la seva solució, perquè són el 90 % de les incidències reals de cron.

Una precisió d'abast: aquí les tasques seran d'una sola línia o crides a ordres existents. Escriure l'script de còpia amb les seves comprovacions i la seva gestió d'errors és el Mòdul 4.

Contingut

  1. Què s'automatitza bé i què s'automatitza malament
  2. Crontab d'usuari i crontab del sistema
  3. Els cinc camps
  4. El conflicte entre dia del mes i dia de la setmana
  5. Fallada clàssica 1: el PATH de cron
  6. Fallada clàssica 2: la sortida que ningú llegeix
  7. Fallada clàssica 3: la zona horària
  8. Depurar una tasca de cron
  9. Solapament i flock
  10. anacron i els temporitzadors de systemd
  11. Cas Tramontana: la còpia nocturna i la purga

  1. Què s'automatitza bé i què s'automatitza malament

Bon candidat Mal candidat
Idempotent: repetir-lo no trenca res Acumula efectes a cada execució
Durada acotada i predictible Pot durar hores indefinidament
Falla de manera visible i registrada Falla en silenci
No necessita decisions humanes Requereix criteri cas per cas
Els seus recursos estan controlats Competeix lliurement amb el servei

La còpia nocturna de Tramontana suspenia a les dues últimes files: no limitava la seva prioritat d'E/S i ningú no en llegia el resultat. Una tasca automàtica que falla en silenci és pitjor que no tenir-la, perquè genera la confiança que la feina està feta. La primera vegada que descobreixes que les còpies porten tres mesos fallant sol ser el dia que en necessites restaurar una.

  1. Crontab d'usuari i crontab del sistema

El dimoni cron (paquet cron a Ubuntu) llegeix diversos llocs diferents:

Ubicació Camp d'usuari S'edita amb Per a què
crontab -e de l'usuari no crontab -e tasques d'un compte
/etc/crontab sí editor + sudo tasques del sistema
/etc/cron.d/<fitxer> sí editor + sudo tasques de paquets o serveis
/etc/cron.{hourly,daily,weekly,monthly}/ — scripts executables tasques periòdiques simples
operador@srv-tramontana:~$ crontab -l
30 3 * * * tar -czf /srv/tramontana/backups/enviaments/nocturna.tar.gz /opt/tramontana

Aquí està la culpable de la incidència d'ahir a la nit.

Opció Efecte
crontab -l llistar
crontab -e editar (fa servir $EDITOR, que vas fixar a 03-01)
crontab -r esborrar el crontab sencer, sense preguntar
crontab fitxer reemplaçar el crontab pel contingut d'un fitxer
crontab -u usuari -l veure el d'un altre usuari (requereix root)

Compte amb crontab -r. No demana confirmació i no hi ha paperera: esborra totes les teves tasques de cop. I és just al costat de -e al teclat. El costum professional és senzill: mantén el teu crontab en un fitxer versionat i carrega'l amb crontab fitxer. Així una pulsació desafortunada costa un crontab ~/cron/operador.cron, no una reconstrucció de memòria.

La diferència clau entre els dos formats és que les línies de /etc/crontab i de /etc/cron.d/ porten un camp extra amb l'usuari que executa la tasca, just abans de l'ordre:

# /etc/cron.d/tramontana
30 3 * * *  operador  /usr/bin/tar -czf /srv/... /opt/...

Oblidar aquest camp és un error freqüent: cron interpreta el nom d'usuari com el primer argument de l'ordre i la tasca falla d'una manera desconcertant.

Els directoris cron.daily i companyia els executa run-parts, que té una peculiaritat: ignora els fitxers el nom dels quals contingui un punt. Un script anomenat copia.sh a /etc/cron.daily/ no s'executarà mai. S'ha de dir copia, sense extensió, i ser executable.

  1. Els cinc camps

┌───── minut         (0-59)
│ ┌─── hora          (0-23)
│ │ ┌─ dia del mes   (1-31)
│ │ │ ┌───── mes     (1-12 o jan-dec)
│ │ │ │ ┌─── dia set (0-7, on 0 i 7 són diumenge, o sun-sat)
│ │ │ │ │
* * * * *  ordre
Sintaxi Significa
* qualsevol valor
5 aquell valor exacte
1,15,30 llista
9-17 rang
*/5 cada 5 unitats des de 0
0-30/10 cada 10, dins del rang
Expressió Quan s'executa
* * * * * cada minut
*/15 * * * * als minuts 0, 15, 30 i 45
30 4 * * * cada dia a les 04:30
0 9-18 * * 1-5 en punt, de 9 a 18, de dilluns a divendres
0 4 1 * * el dia 1 de cada mes a les 04:00
15 2 * * 6 els dissabtes a les 02:15
0 0 1 1,7 * l'1 de gener i l'1 de juliol
*/10 2-4 * * * cada 10 minuts, entre les 2 i les 4
5 0 * * * a les 00:05 (no a les 00:00: evita el minut de màxima concurrència)

Aquesta última fila és un consell real. A les 00:00 en punt arrenca tot el que algú va programar sense pensar; desplaçar-ho cinc minuts evita competir-hi.

Dreceres que substitueixen els cinc camps:

Drecera Equival a
@reboot un cop, en arrencar el sistema
@hourly 0 * * * *
@daily / @midnight 0 0 * * *
@weekly 0 0 * * 0
@monthly 0 0 1 * *
@yearly 0 0 1 1 *

  1. El conflicte entre dia del mes i dia de la setmana

Aquí hi ha una regla que contradiu la intuïció i que fa que moltes tasques s'executin més vegades de les previstes.

Si els camps «dia del mes» i «dia de la setmana» són tots dos diferents de *, es combinen amb OR, no amb AND. La tasca s'executa si es compleix qualsevol dels dos.

0 4 13 * 5     # a les 04:00 els dies 13 I TAMBÉ tots els divendres

La intenció habitual —«només els divendres 13»— exigeix comprovar-ho dins de l'ordre, perquè cron no la sap expressar:

0 4 13 * *  [ "$(date +\%u)" = 5 ] && /ruta/a/l/ordre

(Fixa't en el \%: en un crontab, el símbol % té un significat especial que veurem a l'apartat 6.)

Quan un dels dos és *, no hi ha ambigüitat i mana l'altre. La taula resumeix els quatre casos:

Dia mes Dia setmana Resultat
* * tots els dies
15 * només el dia 15
* 1 només els dilluns
15 1 els dies 15 i a més tots els dilluns

  1. Fallada clàssica 1: el PATH de cron

És, amb diferència, la número u. El símptoma sempre és el mateix: l'ordre funciona perfectament quan l'escrius tu i no fa res des de cron.

La causa la coneixes des de 03-01: cron no llança un shell de login ni interactiu, així que no llegeix /etc/profile, ni ~/.profile, ni ~/.bashrc. Res del teu entorn no existeix allà. El PATH que cron proporciona per defecte és:

PATH=/usr/bin:/bin

Dos directoris. No hi ha /usr/local/bin, ni /usr/sbin, ni per descomptat /home/operador/scripts que vas afegir a 03-01. Tampoc existeixen els teus àlies, ni les teves variables, ni la configuració regional que tens definida.

Si rsync estigués instal·lat a /usr/local/bin, una tasca que l'invoqui pel seu nom fallaria cada vegada, en silenci i sense deixar rastre visible.

Les tres solucions, per ordre de preferència:

  1. Rutes absolutes sempre. Esbrina-les amb command -v i escriu-les tal qual.

    command -v rsync tar find te les dona totes de cop: /usr/bin/rsync, /usr/bin/tar, /usr/bin/find.

  2. Declarar el PATH a la capçalera del crontab. Les assignacions de variables es posen abans de les tasques i s'apliquen a totes:

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
SHELL=/bin/bash
MAILTO=operador
  1. Fer que l'script es carregui l'entorn amb . ~/.profile com a primera línia. Funciona, però acobla la tasca a la configuració personal d'un compte, i això és fràgil.

La regla que apliquem a Tramontana és la 1 reforçada amb la 2: rutes absolutes a les ordres i un PATH explícit a la capçalera, per al que l'ordre pugui invocar internament.

  1. Fallada clàssica 2: la sortida que ningú llegeix

Cron captura stdout i stderr de cada tasca i els envia per correu local a l'usuari propietari. En un servidor sense MTA configurat —com srv-tramontana— aquell correu no arriba enlloc: es descarta o es queda a /var/mail/operador sense que ningú l'obri mai.

Resultat: si no rediriges la sortida, no t'assabentes de res. Ni dels èxits ni, sobretot, de les fallades.

Redirecció Què aconsegueixes
(res) correu local que ningú llegeix
> /dev/null silencia la sortida; els errors sí que generen correu
> /dev/null 2>&1 silenci absolut. Evita-ho
>> /var/log/... 2>&1 el correcte: tot queda registrat
30 4 * * * /usr/bin/rsync -a /home/operador/dades/ /srv/tramontana/backups/enviaments/ >> /var/log/tramontana/cron-copia.log 2>&1

El 2>&1 va al final, pel que vas aprendre a 03-04: primer es redirigeix stdout al fitxer i després es copia aquell destí sobre stderr. A l'inrevés, els errors —que són justament el que t'importa— acabarien al correu fantasma.

Un registre amb data s'aconsegueix anteposant un date:

30 4 * * * { /usr/bin/date '+--- %F %T inici'; /usr/bin/rsync -a /home/operador/dades/ /srv/tramontana/backups/enviaments/; } >> /var/log/tramontana/cron-copia.log 2>&1

MAILTO controla el destí del correu: [email protected] l'envia a una adreça real (si hi ha MTA), i MAILTO="" desactiva l'enviament del tot. La combinació professional és MAILTO="" més redirecció a un fitxer de registre, i que sigui un sistema de monitoratge qui vigili aquell fitxer.

I la peculiaritat del %: en un crontab, % s'interpreta com un salt de línia que alimenta l'entrada estàndard de l'ordre. Per això date +%F dins d'un crontab s'ha d'escriure date +\%F. És una font d'errors desproporcionada per al poc habitual que és el detall.

  1. Fallada clàssica 3: la zona horària

cron fa servir la zona horària del sistema, no la de l'usuari. Comprova-la sempre:

operador@srv-tramontana:~$ timedatectl | grep -i 'time zone'
               Time zone: Europe/Madrid (CEST, +0200)

A les zones amb horari d'estiu hi ha dos dies l'any problemàtics. Quan el rellotge s'avança al març, les 02:30 no existeixen: una tasca programada a aquella hora no s'executa aquell dia. Quan s'endarrereix a l'octubre, les 02:30 passen dues vegades, i segons la implementació la tasca es pot executar dues vegades.

Tres maneres de protegir-se:

  • Programar fora de la franja 01:00–03:00. És la solució més simple i la que resol el problema de debò.
  • Fer servir UTC al servidor (sudo timedatectl set-timezone UTC), pràctica habitual en servidors, a canvi d'haver de traduir mentalment els horaris.
  • Declarar CRON_TZ=UTC a la capçalera del crontab, que fixa la zona només per a aquelles tasques.

Aquí hi ha una coincidència que convé subratllar: la còpia de Tramontana estava a les 03:30, dins de la franja de risc, i a més xocava amb el pic de càrrega. Moure-la resol dos problemes de cop.

  1. Depurar una tasca de cron

flowchart TD
    A["La tasca no fa el que s'espera"] --> B{"S'ha executat?<br/>grep CRON /var/log/syslog"}
    B -->|No| C["Revisa la sintaxi dels 5 camps<br/>i que el crontab estigui carregat"]
    B -->|Sí| D{"Hi ha registre<br/>al teu fitxer de log?"}
    D -->|No| E["Falta la redirecció:<br/>afegeix >> log 2>&1"]
    D -->|Sí| F{"Què diu l'error?"}
    F -->|"ordre no trobada"| G["PATH: fes servir rutes absolutes"]
    F -->|"permís denegat"| H["Usuari equivocat<br/>o permisos del destí"]
    F -->|"un altre"| I["Reprodueix amb env -i"]

On es registra. El dimoni anota cada execució al syslog:

operador@srv-tramontana:~$ grep CRON /var/log/syslog | tail -3
Aug 18 03:30:01 srv-tramontana CRON[2210]: (operador) CMD (tar -czf /srv/tramontana/backups/enviaments/nocturna.tar.gz /opt/tramontana)
Aug 18 04:30:01 srv-tramontana CRON[2455]: (operador) CMD (/usr/bin/rsync -a /home/operador/dades/ /srv/tramontana/backups/enviaments/)
Aug 18 04:30:02 srv-tramontana CRON[2455]: (CRON) info (No MTA installed, discarding output)

Tres coses: la còpia va arrencar a les 03:30:01, coincidint amb la incidència; l'rsync també va córrer; i el missatge «No MTA installed, discarding output» és cron dient-te literalment que ha tirat la sortida a les escombraries. Aquí hi ha la fallada 2, confessada al mateix registre.

Aquest registre et diu si la tasca s'ha executat, però no si ha funcionat: cron no comprova el codi de sortida. Per a això cal el teu propi fitxer de registre.

Abocar l'entorn de cron. El truc definitiu per a la fallada 1: programa una tasca temporal que guardi el seu entorn i compara'l amb el teu.

* * * * * /usr/bin/env > /tmp/entorn-cron.txt 2>&1
operador@srv-tramontana:~$ cat /tmp/entorn-cron.txt
SHELL=/bin/sh
PWD=/home/operador
LOGNAME=operador
PATH=/usr/bin:/bin
HOME=/home/operador

Cinc variables. Ni LANG, ni el teu PATH ampliat. Fixa't a més que SHELL és /bin/sh, no bash: les construccions específiques de Bash poden fallar. Si les necessites, declara SHELL=/bin/bash a la capçalera.

Provar l'ordre amb l'entorn de cron, sense esperar que es dispari:

operador@srv-tramontana:~$ env -i SHELL=/bin/sh PATH=/usr/bin:/bin HOME=/home/operador \
    /bin/sh -c 'rsync -a /home/operador/dades/ /srv/tramontana/backups/enviaments/'
/bin/sh: 1: rsync: not found

Reproduït en dos segons. env -i arrenca l'ordre sense cap variable heretada i li afegeix només les que li indiquis: és una simulació fidel de cron. Qualsevol tasca nova s'hauria de provar així abans de programar-la.

  1. Solapament i flock

Si una execució dura més que l'interval, cron llança la següent igualment. Dues còpies escrivint al mateix fitxer produeixen un fitxer corromput; dues purgues simultànies poden trepitjar-se mútuament.

flock resol el problema amb un fitxer de bloqueig:

30 4 * * * /usr/bin/flock -n /var/lock/tramontana-copia.lock /usr/bin/tar -czf /srv/tramontana/backups/enviaments/nocturna.tar.gz /opt/tramontana/app/ >> /var/log/tramontana/cron-copia.log 2>&1
Opció Comportament si el bloqueig està pres
-n surt immediatament amb codi 1
-w 60 espera fins a 60 segons i després es rendeix
(res) espera indefinidament

-n és gairebé sempre l'opció correcta per a una tasca periòdica: si l'anterior continua en marxa, aquesta hi sobra. Sense -n, les execucions es van encuant i acabes amb vint processos esperant.

El bloqueig s'allibera sol quan el procés acaba, fins i tot si mor de cop, perquè el gestiona el nucli a través del descriptor de fitxer. No hi ha fitxers de bloqueig orfes per netejar a mà, que és exactament el problema d'implementar-ho amb un touch i un rm.

  1. anacron i els temporitzadors de systemd

cron suposa que la màquina està encesa a l'hora prevista. Si el servidor estava apagat, la tasca no es recupera. anacron cobreix aquest buit: treballa amb granularitat de dies i, en arrencar, executa el que va quedar pendent. A Ubuntu, cron.daily, cron.weekly i cron.monthly els gestiona anacron precisament per això.

cron anacron temporitzador de systemd
Granularitat minuts dies segons
Recupera el que s'ha perdut no sí sí (Persistent=true)
Registre syslog syslog journalctl -u <unitat>
Dependències entre tasques no no sí
Aleatoritzar l'arrencada no sí RandomizedDelaySec
Complexitat mínima baixa alta (dos fitxers per tasca)

Quan triar cadascun. cron per al que és simple i periòdic en un servidor sempre encès: és universal, cap en una línia i qualsevol administrador l'entén. anacron per a portàtils i màquines que s'apaguen. Els temporitzadors de systemd quan necessites dependències entre unitats, control de recursos, reintents o el registre integrat del sistema; s'estudien a 05-05. Per a la còpia de Tramontana, cron és suficient i més llegible.

  1. Cas Tramontana: la còpia nocturna i la purga

Refem la tasca culpable aplicant-hi tot l'anterior. El crontab es manté en un fitxer versionat i es carrega des d'allà.

operador@srv-tramontana:~$ crontab -l > ~/cron-operador.bak-$(date +%F)
operador@srv-tramontana:~$ nano ~/cron/operador.cron
# Crontab d'operador — Tramontana Reserves
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=""
CRON_TZ=Europe/Madrid

# Còpia diària de dades i del release actiu. 04:20 (fora del pic i del canvi d'hora).
20 4 * * * /usr/bin/flock -n /var/lock/tramontana-copia.lock /usr/bin/ionice -c 3 /usr/bin/tar -czf /srv/tramontana/backups/enviaments/dades-$(/usr/bin/date +\%F).tar.gz /home/operador/dades /opt/tramontana/app/ >> /var/log/tramontana/cron-copia.log 2>&1

# Purga de còpies de més de 30 dies. Diumenges a les 05:10.
10 5 * * 0 /usr/bin/find /srv/tramontana/backups/enviaments -type f -name 'dades-*.tar.gz' -mtime +30 -delete >> /var/log/tramontana/cron-purga.log 2>&1

Es carrega amb crontab ~/cron/operador.cron i es comprova amb crontab -l. Repassa cada decisió, perquè cadascuna corregeix un problema concret:

  • 04:20 en comptes de 03:30: fora del pic d'errors que vas identificar a 03-05 i fora de la franja del canvi d'hora.
  • flock -n: si una còpia anterior continua en marxa, aquesta no arrenca.
  • ionice -c 3: la còpia només fa servir el disc quan el servei no el necessita. És la correcció directa de la incidència de 03-06.
  • /opt/tramontana/app/ amb barra final en comptes de /opt/tramontana sencer: app és l'enllaç simbòlic al release actiu, i la barra fa que tar segueixi l'enllaç. Es copia un release en comptes de quatre, i sempre el que està servint.
  • Nom amb data: dades-2026-08-18.tar.gz, amb \%F escapat. Cada dia el seu fitxer, en comptes de sobreescriure l'única còpia que tenies.
  • >> ... 2>&1 a totes dues tasques: tot queda registrat, amb el 2>&1 al final.
  • Rutes absolutes a totes les ordres, inclòs el date de dins de la substitució.
  • La purga en tasca a part i amb find -mtime +30: saps de 03-03 que això significa 31 dies o més, marge de sobres per a una retenció mensual.

Verificació abans d'anar cap a casa: es prova l'ordre amb l'entorn de cron i es comprova el resultat.

operador@srv-tramontana:~$ env -i SHELL=/bin/bash PATH=/usr/bin:/bin HOME=/home/operador /bin/bash -c \
    '/usr/bin/flock -n /var/lock/tramontana-copia.lock /usr/bin/ionice -c 3 /usr/bin/tar -czf /tmp/prova.tar.gz /home/operador/dades /opt/tramontana/app/'
operador@srv-tramontana:~$ echo $?; ls -lh /tmp/prova.tar.gz
0
-rw-r----- 1 operador operador 47M Aug 18 13:40 /tmp/prova.tar.gz
operador@srv-tramontana:~$ tar -tzvf /tmp/prova.tar.gz | head -2
drwxr-x--- operador/tramontana 0 2026-08-18 09:14 home/operador/dades/
-rw-r----- operador/tramontana 1284 2026-08-14 11:02 home/operador/dades/reserves.csv

Codi 0, 47 MB —un release, no quatre— i tar -tzvf confirma que el contingut és l'esperat abans de donar la tasca per bona. És la convenció del curs aplicada aquí: mirar dins del fitxer abans de confiar-hi.

Informe per a la Marta. La còpia nocturna s'ha reprogramat a les 04:20, amb la prioritat de disc més baixa i limitada al release en servei en comptes dels quatre. Això protegeix que la còpia torni a deixar l'aplicació sense disc, que dues còpies se solapin i la pèrdua de la còpia anterior en generar-se la nova. No protegeix davant d'una fallada de la còpia: encara ningú no vigila /var/log/tramontana/cron-copia.log, de manera que un error continuaria passant desapercebut, ni tampoc davant de la pèrdua del servidor sencer, perquè les còpies continuen al mateix disc. Totes dues coses requereixen decisions que excedeixen l'ajust tècnic i s'aborden al mòdul d'administració.

Errors Comuns i Consells

  • crontab -r en comptes de -e. Esborra tot sense preguntar. Mantén el crontab en un fitxer i carrega'l amb crontab fitxer.
  • Oblidar el camp d'usuari a /etc/cron.d/. Cron el pren com a argument de l'ordre.
  • Posar una extensió a un script de /etc/cron.daily/. run-parts ignora els noms amb punt.
  • Suposar que existeix el teu PATH. Cron dona /usr/bin:/bin i res més. Rutes absolutes.
  • % sense escapar. Dins d'un crontab, % és un salt de línia. Escriu \%.
  • No redirigir la sortida. Sense >> log 2>&1 les fallades desapareixen.
  • Posar 2>&1 abans de la redirecció de sortida. Va al final, sempre.
  • Programar entre les 02:00 i les 03:00. És la franja del canvi d'hora.
  • * * * * * de prova i oblidar-se de treure'l. Deixa una tasca corrent cada minut per sempre.
  • Consell: documenta cada tasca amb un comentari que digui què fa i per què a aquella hora. D'aquí a un any ho agrairàs tu, no un altre.
  • Consell: fes que la tasca escrigui una marca d'èxit amb data. Comprovar «l'última línia del registre és d'avui?» és una revisió trivial i detecta el 90 % dels problemes.

Exercicis

Exercici 1. Escriu les expressions de cron per a: cada 20 minuts entre les 8 i les 20 els dies laborables; l'últim dia de cada mes a les 23:50; i a les 06:15 els dies 1 i 15. Justifica el segon cas, que té truc.

Exercici 2. Programa una tasca que registri cada hora el nombre d'errors 500 d'errors.log a /var/log/tramontana/errors-500.log juntament amb la data. Aplica les tres proteccions contra les fallades clàssiques i demostra que funcionaria a l'entorn de cron abans d'instal·lar-la.

Exercici 3. Una tasca programada */5 * * * * /home/operador/scripts/sincronitzar >> /tmp/sync.log 2>&1 no produeix cap línia al seu registre, encara que l'ordre funciona quan l'executes tu. Descriu el procediment complet de diagnòstic, en ordre, indicant què comprovaries a cada pas i què conclouries de cada resultat.

Solucions

Solució 1.

*/20 8-20 * * 1-5   # cada 20 min, de 8 a 20, de dilluns a divendres
15 6 1,15 * *       # a les 06:15 els dies 1 i 15

El segon, «l'últim dia de cada mes», no es pot expressar amb els cinc camps: cron no sap quants dies té el mes, i 31 es saltaria febrer, abril, juny, setembre i novembre. La solució idiomàtica és programar-ho cada dia i deixar que l'ordre decideixi:

50 23 * * * [ "$(/usr/bin/date -d tomorrow +\%d)" = 01 ] && /ruta/ordre

Es pregunta quin dia serà demà: si és dia 1, avui és l'últim del mes, sigui quina sigui la seva llargada i encara que l'any sigui de traspàs. És un bon exemple de la frontera de cron: quan la condició no cap en els cinc camps, s'executa diàriament i es comprova a dins. El \% va escapat, com sempre.

Solució 2. Primer es prova l'ordre a l'entorn de cron:

operador@srv-tramontana:~$ env -i PATH=/usr/bin:/bin HOME=/home/operador /bin/sh -c \
    'echo "$(/usr/bin/date +%F\ %T) $(/usr/bin/grep -c "ERROR 500" /var/log/tramontana/errors.log)"'
2026-08-18 13:52 41

Funciona amb només /usr/bin:/bin al PATH, per tant no depenem de res que cron no tingui. Ara la línia de crontab:

0 * * * * /usr/bin/flock -n /var/lock/errors-500.lock /bin/sh -c 'echo "$(/usr/bin/date +\%F\ \%T) $(/usr/bin/grep -c \"ERROR 500\" /var/log/tramontana/errors.log)"' >> /var/log/tramontana/errors-500.log 2>&1

Les tres proteccions: rutes absolutes per a date i grep, de manera que el PATH mínim no importi; >> ... 2>&1 perquè tant el resultat com qualsevol error quedin al fitxer i no a un correu que ningú llegeix; i CRON_TZ declarat a la capçalera del crontab —juntament amb l'elecció del minut 0 de cada hora, lluny de la franja del canvi horari— perquè les marques de temps siguin coherents. S'hi afegeix flock perquè és un costum barat, encara que aquí el risc de solapament sigui mínim. I els % van escapats: sense les barres, cron tallaria l'ordre al primer % i li passaria la resta com a entrada estàndard, que és una fallada especialment difícil de reconèixer.

Una línia que comença a acumular escapades com aquesta és el senyal que el contingut demana un script propi. Això és el que resoldrà el Mòdul 4.

Solució 3. El procediment, en ordre, del més extern al més intern:

  1. Existeix la tasca? crontab -l | grep sincronitzar. Si no apareix, es va editar un altre crontab —el de root, per exemple— o un crontab -r se la va endur.
  2. S'està executant? grep CRON /var/log/syslog | grep sincronitzar | tail -3. Si no hi ha entrades, cron no la llança: revisa la sintaxi dels camps i que el dimoni estigui actiu. Si n'hi ha, cron la llança i el problema és més endins.
  3. Existeix el fitxer de registre i amb quins permisos? ls -l /tmp/sync.log. Un registre buit però existent confirma que la redirecció funciona i que l'ordre no escriu res; que el fitxer no existeixi apunta que l'ordre ni tan sols va arribar a arrencar.
  4. És executable i amb la ruta correcta? ls -l /home/operador/scripts/sincronitzar. Sense el bit x, cron obté «permission denied». I aquí hi ha el sospitós principal: la tasca fa servir una ruta absoluta a l'script, però l'script per dins probablement invoca ordres pel seu nom, i aquestes sí que depenen del PATH.
  5. Reproduir amb l'entorn de cron: env -i PATH=/usr/bin:/bin HOME=/home/operador /bin/sh /home/operador/scripts/sincronitzar. Aquest pas gairebé sempre reprodueix la fallada a l'instant.
  6. Verificar l'escriptura sobre el destí amb sudo -u operador touch al directori de destí, per si la tasca corre amb un usuari diferent del que et penses.

La conclusió més probable és la del pas 5. I hi ha una pista que hi apunta des del principi: si el registre està buit en comptes de contenir un missatge d'error, l'ordre no va arribar a produir sortida, cosa que encaixa amb un shell que ni tan sols va poder arrencar el binari. Un registre buit és informació, no absència d'informació.

Conclusió

Has convertit una tasca automàtica perillosa en una tasca automàtica defensable.

  • Saps què s'automatitza bé: el que és idempotent, acotat, amb recursos controlats i amb fallada visible. I distingeixes el crontab d'usuari del crontab del sistema, amb el seu camp extra d'usuari, i coneixes run-parts i la seva mania amb els punts als noms.
  • Domines els cinc camps amb llistes, rangs, passos i dreceres, i saps que dia del mes i dia de la setmana es combinen amb OR, no amb AND.
  • Tens resoltes les tres fallades clàssiques: el PATH mínim de cron —rutes absolutes sempre—, la sortida que ningú llegeix —>> log 2>&1 amb el 2>&1 al final— i la zona horària amb la seva franja de risc entre les 02:00 i les 03:00.
  • Depures una tasca amb mètode: grep CRON /var/log/syslog per saber si s'ha executat, el teu propi registre per saber si ha funcionat, l'abocament de l'entorn amb env i la reproducció exacta amb env -i.
  • Evites el solapament amb flock -n, sabent que el bloqueig l'allibera el nucli i no deixa restes.
  • Coneixes anacron per a màquines que s'apaguen i saps quan un temporitzador de systemd compensa la seva complexitat.
  • I has reprogramat la còpia de Tramontana amb hora nova, bloqueig, prioritat d'E/S, abast reduït al release actiu, nom amb data i registre, amb la purga en tasca a part i un informe honest sobre el que la mesura no cobreix.

Queda un front sense tocar. Tot el que has fet fins ara passa dins de srv-tramontana, i un servidor només existeix per a qui hi pugui arribar. L'última lliçó del mòdul, Comandes de Xarxa, et dona les eines per mirar cap enfora: ip per llegir la configuració real de la màquina, ping, traceroute i mtr per al camí, dig i /etc/hosts per a la resolució de noms, ss per saber quins ports escolten i qui els ocupa, i curl per comprovar si el servei respon de debò. Tot plegat ordenat en una metodologia de diagnòstic per capes que aplicaràs al cas que t'espera: la Marta avisa que el web de reserves «no carrega», i cal esbrinar exactament on és el tall.

Curs de Linux: De Principiant a Administrador de Sistemes

Mòdul 1: Introducció a Linux

Mòdul 2: Comandes Bàsiques de Linux

Mòdul 3: Habilitats Avançades en la Línia de Comandes

Mòdul 4: Scripting en Shell

Mòdul 5: Administració del Sistema

Mòdul 6: Xarxes i Seguretat

Mòdul 7: Temes Avançats

Mòdul 8: Projectes Pràctics

© Copyright 2026. Tots els drets reservats