El toolkit està complet i programat, però cron comença a quedar-se curt. No sap esperar que la xarxa estigui a punt abans de llançar el vigilant. No recupera l'execució de l'informe si el servidor estava apagat a les 06:30. No limita la memòria d'una tasca que es desmandi, ni aïlla el seu accés al sistema de fitxers. I el seu registre està dispers en quatre registres que cal consultar un a un. systemd resol les quatre coses, a canvi de més fitxers i més sintaxi. Aquesta lliçó ensenya el just de systemd que necessita un script de Bash: com es declara un servei, com es programa amb un temporitzador, i quan val la pena migrar de cron i quan no.
Contingut
- Què és systemd, unitats i on viuen
- Anatomia d'un
.service, ioneshotenfront desimple - Anatomia d'un
.timer OnCalendari com validar-loPersistent=true: allò que cron no pot fer- Cron enfront dels temporitzadors: la taula honesta
- Ordres del dia a dia
- Endurir una unitat
- Serveis de llarga durada escrits en Bash
- Unitats d'usuari i
loginctl enable-linger - Migrar una entrada de cron pas a pas
- Aplicació: el toolkit sobre systemd
- Què és systemd, unitats i on viuen
systemd és el procés número 1 de gairebé totes les distribucions actuals: el primer que arrenca el nucli i el que posa en marxa tota la resta. La seva feina és gestionar unitats —serveis, muntatges, sòcols, temporitzadors— i les dependències entre elles: què ha d'estar a punt abans de què. Un script de Bash se'l troba per tres camins: els temporitzadors com a alternativa moderna a cron, els serveis quan alguna cosa ha de córrer contínuament i reiniciar-se si mor, i la consulta —ja has fet servir systemctl is-active a 06-03 i journalctl -u cron a 07-01 sense anomenar-lo systemd—. No cal dominar-lo: amb les quinze directives d'aquesta lliçó cobreixes el 95 % del que necessita un script d'operacions. Una unitat és un fitxer de text amb format INI. Els tipus que ens interessen són .service (un procés que s'executa), .timer (quan s'activa una altra unitat) i .target (un punt de sincronització, com network-online.target). I tres ubicacions, amb precedència de menor a major:
| Camí | Qui hi mana | Ús |
|---|---|---|
/usr/lib/systemd/system/ |
Els paquets de la distribució | No editar: una actualització ho sobreescriu |
/etc/systemd/system/ |
L'administrador | Aquí van les teves unitats; guanya sobre l'anterior |
~/.config/systemd/user/ |
Cada usuari, les seves | Unitats d'usuari, sense sudo (apartat 10) |
La regla és la de 05-06: el que porta el sistema no es toca, el teu va a /etc. Si necessites canviar una sola directiva d'una unitat del sistema, systemctl edit nom.service crea un fragment a …/nom.service.d/override.conf que s'hi superposa sense substituir l'original.
- Anatomia d'un
.service, i oneshot enfront de simple
.service, i oneshot enfront de simple# /etc/systemd/system/veloz-informe.service
[Unit]
Description=Informe diari d'enviaments de Veloz Envios
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
User=veloz
Group=veloz
WorkingDirectory=/home/veloz/veloz-ops
EnvironmentFile=-/home/veloz/veloz-ops/etc/veloz-ops.conf
Environment=LC_ALL=C
ExecStart=/home/veloz/veloz-ops/bin/informe-diari.sh
TimeoutStartSec=900
StandardOutput=journal
StandardError=journalA [Unit] van metadades i dependències: Description és el que veuràs a systemctl status, i After=network-online.target significa «no arrenquis abans que la xarxa estigui a punt», amb Wants= per activar-la si no ho estava —això és exactament el que cron no sap fer amb @reboot (07-01)—. A [Service] va com s'executa. Type=oneshot per a un procés que fa la seva feina i acaba (el bloc següent); User/Group per no córrer com a root si no cal; WorkingDirectory fixa el directori de treball, encara que igualment faràs servir camins absoluts; EnvironmentFile=-/cami carrega parells CLAU=valor com a entorn i el guionet inicial evita que falli si el fitxer no existeix; Environment= defineix una variable solta i es repeteix tantes vegades com calgui; TimeoutStartSec és el timeout de 07-02 integrat; i StandardOutput/StandardError decideixen on va la sortida, amb journal com a valor per defecte avui. Dos avisos sobre ExecStart. El camí ha de ser absolut sempre: systemd no té cap PATH que valgui i fallarà amb «No such file or directory» encara que l'script sigui al teu. I no hi ha shell: ExecStart=/bin/el-meu.sh > /tmp/sortida.log no redirigeix res, perquè el > se li passa a l'script com a argument literal; si necessites construccions de shell, invoca-les explícitament amb bash -c '…'. A la pràctica no cal, perquè StandardOutput=journal ja captura la sortida. I falta la secció [Install], que diu què passa en fer enable: en un servei disparat per un temporitzador no s'hi posa, perquè no volem que arrenqui en iniciar el sistema sinó quan ho digui el temporitzador.
Type=oneshot enfront de Type=simple
Aquesta elecció confon tothom, i equivocar-se produeix símptomes estranys:
Type=simple |
Type=oneshot |
|
|---|---|---|
| Per a què | Processos de llarga durada | Tasques que acaben |
| Es considera «arrencat» | Tan bon punt llança el procés | Quan el procés acaba amb èxit |
| Estat en acabar | failed (ha mort inesperadament) |
inactive (dead), que és el correcte |
| Amb temporitzadors | Malament | Sí, és el normal (admet diversos ExecStart) |
Les teves tasques d'operacions són totes oneshot: fan la seva feina i surten. Un Type=simple per a elles faria que systemctl status mostrés la unitat com a fallida cada vegada que acaba correctament; a l'inrevés, un servei de llarga durada declarat oneshot deixaria systemd esperant eternament que «arrenqui». RemainAfterExit=yes és un complement d'oneshot que deixa la unitat com a active en acabar, per a tasques que estableixen un estat (muntar alguna cosa, aplicar una configuració), no per a les periòdiques.
- Anatomia d'un
.timer
.timerUn temporitzador activa una altra unitat en un moment donat, i la relació és pel nom: veloz-informe.timer dispara veloz-informe.service sense declarar-ho (es pot canviar amb Unit=).
# /etc/systemd/system/veloz-informe.timer
[Unit]
Description=Programa l'informe diari de Veloz Envios a les 06:30
[Timer]
OnCalendar=*-*-* 06:30:00
Persistent=true
RandomizedDelaySec=120
AccuracySec=1s
[Install]
WantedBy=timers.targetLes directives de [Timer] venen en dues famílies. La de rellotge és OnCalendar=, que dispara en moments concrets com cron. Les relatives són OnBootSec= (tant de temps després d'arrencar el sistema), OnStartupSec= (després d'arrencar systemd), OnUnitActiveSec= (després de l'última execució) i OnUnitInactiveSec= (després que acabés). A això s'hi sumen Persistent=true (apartat 5), RandomizedDelaySec= i AccuracySec=. OnUnitActiveSec mereix atenció perquè resol una cosa que cron fa malament. OnBootSec=5min més OnUnitActiveSec=5min significa «cinc minuts després d'arrencar, i després cada cinc minuts des que va acabar l'anterior». Amb cron, */5 dispara segons el rellotge encara que l'execució prèvia segueixi viva; aquí l'interval es compta des de l'execució real, així que no hi ha encavalcament per disseny i el flock deixa de ser imprescindible —tot i que convé mantenir-lo, perquè també protegeix de les execucions a mà—. RandomizedDelaySec és la resposta al problema de @daily: si vint servidors tenen el mateix temporitzador, el retard aleatori reparteix la càrrega. I AccuracySec permet a systemd agrupar activacions per estalviar energia; per defecte és un minut, així que si necessites puntualitat posa'l a 1s explícitament. Aquest és també el gran absent de cron: la granularitat. OnUnitActiveSec=30s és perfectament vàlid; a cron, «cada 30 segons» no existeix.
OnCalendar i com validar-lo
OnCalendar i com validar-loLa sintaxi és DiaDeSetmana Any-Mes-Dia Hora:Minut:Segon, amb * per a «qualsevol» i /N per a passos:
| Expressió | Significat | A cron |
|---|---|---|
*-*-* 06:30:00 |
Cada dia a les 06:30 | 30 6 * * * |
daily / hourly |
Mitjanit / cada hora en punt | @daily / @hourly |
*-*-* *:0/5:00 (o *:0/5) |
Cada 5 minuts | */5 * * * * |
Mon..Fri *-*-* 09:00:00 / *-*-01 04:00:00 |
Feiners a les 09:00 / el dia 1 de cada mes | 0 9 * * 1-5 / 0 4 1 * * |
Mon *-*-01..07 05:00:00 |
El primer dilluns de cada mes | (no es pot expressar) |
I aquí ve una de les millors raons per fer servir temporitzadors: pots comprovar l'expressió abans d'instal·lar-la amb systemd-analyze calendar '*-*-* 06:30:00' --iterations=3.
Et diu si l'expressió és vàlida, com la interpreta i quan s'executaria; amb --iterations mostra les vegades següents, que és la manera definitiva de comprovar que «cada cinc minuts» significa el que creus. Cron no ofereix res de semblant: allà l'única manera de comprovar-ho és esperar. OnCalendar accepta a més sufixos de zona horària (Mon *-*-* 03:00:00 UTC), cosa que resol netament el problema del canvi d'hora que vas veure a 07-01.
Persistent=true: allò que cron no pot fer
Persistent=true: allò que cron no pot ferEscenari real: la còpia de seguretat està programada a les 03:15 i el servidor passa la nit apagat per manteniment, arrencant a les 09:00. Amb cron, l'execució de les 03:15 simplement no va ocórrer, i ningú no ho notarà fins que calgui aquella còpia. Persistent=true canvia això: systemd desa en disc quan es va executar per última vegada cada temporitzador i, en arrencar, comprova si es va saltar alguna activació; si és així, la llança immediatament. És la funcionalitat d'anacron (07-01) integrada, sense cap eina a part i amb granularitat completa. Ha d'estar posat a tota tasca l'execució de la qual importi —informes, còpies, neteges— i ha d'estar tret a les que només tenen sentit al seu moment: una comprovació d'estat de fa vuit hores no aporta res en arrencar. Combina'l amb RandomizedDelaySec perquè les tasques endarrerides no es llancin totes alhora.
- Cron enfront dels temporitzadors: la taula honesta
| Criteri | cron |
Temporitzador de systemd |
|---|---|---|
| Complexitat per començar | Una línia | Dos fitxers i tres ordres |
| Validar l'horari / granularitat | No es pot / un minut | systemd-analyze calendar / un segon |
| Execucions perdudes | Es perden | Persistent=true les recupera |
| Dependències (xarxa, muntatges) | No les coneix | After=, Wants=, Requires= |
| Registre | On tu redirigeixis, un fitxer per tasca | Journal centralitzat, journalctl -u |
| Encavalcament | Cal posar-hi flock |
No s'encavalca per disseny |
| Entorn | Mínim i sorprenent | Explícit amb Environment/EnvironmentFile |
| Aïllament i límits | No | MemoryMax, ProtectSystem, PrivateTmp… |
| Portabilitat | Qualsevol Unix | Només sistemes amb systemd |
La conclusió assenyada: cron per al que és simple i portable, temporitzadors per al que importa. Una neteja de temporals segueix estant bé a cron; una còpia de seguretat que no s'ha de perdre, una tasca que necessita la xarxa o un servei que s'ha de reiniciar sol demanen un temporitzador. No hi ha obligació de migrar-ho tot: conviure és normal.
- Ordres del dia a dia
Després de crear o modificar qualsevol unitat cal recarregar amb sudo systemctl daemon-reload; oblidar-ho és l'error número u amb systemd.
| Ordre | Què fa |
|---|---|
systemctl enable --now x.timer / start x.service |
Activa el temporitzador i l'arrenca ja / executa la tasca ara, a mà |
systemctl status x.service / list-timers --all |
Estat i últimes línies / tots els temporitzadors amb la propera i l'última execució |
systemctl cat x.timer / systemd-analyze verify x.service |
La unitat tal com la veu systemd / errors de sintaxi |
journalctl -u veloz-informe --since today -p err |
Els errors d'avui d'aquella tasca |
list-timers és la vista que substitueix crontab -l, i dona bastant més informació:
NEXT LEFT LAST PASSED UNIT Mon 2026-08-03 18:35:00 CEST 4min 12s Mon 2026-08-03 18:30:00 CEST 47s ago veloz-vigilant.timer Tue 2026-08-04 03:15:00 CEST 8h 44min Mon 2026-08-03 03:15:00 CEST 15h ago veloz-copia.timer
D'un cop d'ull saps què ve, quan va ser l'últim i si alguna cosa fa massa que no s'executa: aquell LAST és justament la dada que check_copia (07-04) havia de deduir mirant directoris. I systemctl start mereix un elogi a part, perquè prova la tasca exactament en les condicions en què s'executarà —mateix usuari, mateix entorn, mateixos límits—: és l'env -i de 07-01, però de debò.
- Endurir una unitat
Un avantatge que cron no pot oferir: limitar el que la tasca pot fer encara que tingui una fallada.
NoNewPrivileges=true # no pot escalar privilegis ni amb setuid
ProtectSystem=strict # tot el sistema de fitxers en nomes lectura...
ReadWritePaths=/copies /home/veloz/veloz-ops/logs # ...llevat d'aquests camins
ProtectHome=read-only # els /home d'altres usuaris, nomes lectura
PrivateTmp=true # un /tmp propi i aillat; MemoryMax=512M posa sostre de memoriaAmb això, una fallada al teu script de còpia no pot escriure fora de /copies i logs/, i PrivateTmp elimina tota una família d'atacs per fitxers temporals predictibles: defensa en profunditat gairebé de franc, amb les implicacions completes a 08-03. Comença suau (ProtectSystem=full, PrivateTmp=true, NoNewPrivileges=true) i endureix després provant amb systemctl start: si la tasca deixa de funcionar, ja saps quin camí falta a ReadWritePaths.
- Serveis de llarga durada escrits en Bash
De vegades sí que vols un procés permanent: un vigilant que comprova cada 10 segons, o alguna cosa que consumeix una cua. La unitat passa a Type=simple i hi afegeix Restart=on-failure (torna a llançar si acaba amb codi diferent de zero; always torna a llançar fins i tot després d'una sortida neta), RestartSec=10 per esperar entre intents, i StartLimitBurst=5 amb StartLimitIntervalSec=300 per evitar el bucle infinit: si falla cinc vegades en cinc minuts, systemd es rendeix i deixa la unitat en failed, que és el correcte perquè un reinici que no arregla res només amaga el problema. Restart= no arregla un script mal escrit: reiniciar cada 10 segons alguna cosa que falla per un camí mal posat només omple el journal. A més, ha d'atendre SIGTERM, que és el que envia systemctl stop, reprenent el trap de 05-03:
SEGUIR=1
termina() { veloz_log_info "SIGTERM rebut; acabant ordenadament"; SEGUIR=0; }
trap termina TERM INT
while (( SEGUIR )); do
processa_lot || veloz_log_warn "lot fallit; continuo"
for (( i = 0; i < 10 && SEGUIR; i++ )); do sleep 1; done
done
veloz_log_info "sortida neta"; exit 0Dos detalls el fan funcionar. La bandera SEGUIR permet acabar la feina en curs abans de sortir, en lloc de morir a mitges deixant un fitxer corrupte. I l'espera es trosseja en sleep d'un segon en lloc de sleep 10, perquè Bash no interromp un sleep llarg fins que acaba: amb sleep 10, systemctl stop trigaria fins a deu segons a fer efecte i systemd acabaria enviant SIGKILL. Si l'script no respon a SIGTERM, systemd espera TimeoutStopSec (90 s per defecte) i després mata a la brava, amb tota la corrupció que això pugui causar.
- Unitats d'usuari i
loginctl enable-linger
loginctl enable-lingerNo tot necessita sudo: cada usuari té la seva instància de systemd i les seves unitats a ~/.config/systemd/user/.
mkdir -p ~/.config/systemd/user # copiar-hi les unitats, sense User= ni Group=
systemctl --user daemon-reload && systemctl --user enable --now veloz-informe.timerÉs igual amb --user afegit i sense User=/Group=, ja que corre com tu; l'avantatge és que no necessites privilegis i la unitat viu al teu $HOME, versionable amb el toolkit. Hi ha un parany: per defecte, la instància d'usuari mor quan tanques la sessió, així que els teus temporitzadors deixen de disparar-se. La solució és sudo loginctl enable-linger veloz —linger és «romandre»—, que manté la instància d'aquell usuari encara que no tingui sessió oberta; sense ella, una unitat d'usuari funciona mentre estàs connectat i misteriosament deixa de funcionar quan te'n vas. Per a tasques de servidor l'habitual segueix sent unitats del sistema amb User=veloz.
- Migrar una entrada de cron pas a pas
Agafem la línia del vigilant (*/5 * * * * flock -n … vigilant.sh >> … 2>&1) en sis passos. Pas 1: el servei, on va tot el que no sigui l'horari; és el de l'apartat 2 canviant aquestes directives.
# veloz-vigilant.service
After=network-online.target veloz-api.service
ExecStart=/home/veloz/veloz-ops/bin/vigilant.sh
TimeoutStartSec=120
SuccessExitStatus=1
# veloz-vigilant.timer
[Timer]
OnBootSec=2min
OnUnitActiveSec=5min
AccuracySec=10s
[Install]
WantedBy=timers.targetSuccessExitStatus=1 és un ajust fi: el vigilant retorna 1 quan hi ha algun WARNING, i no volem que systemd marqui la unitat com a fallida per un avís; la redirecció al registre desapareix perquè la sortida va al journal. Pas 2: el temporitzador, on es tria OnUnitActiveSec en lloc d'OnCalendar=*:0/5 perquè l'interval es compti des que va acabar l'execució anterior i no s'encavalquin mai, sense Persistent=true perquè una comprovació endarrerida no interessa. Pas 3: validar amb systemd-analyze verify …{service,timer}. Pas 4: recarregar i provar a mà amb daemon-reload, systemctl start veloz-vigilant.service i journalctl -u veloz-vigilant -n 30 --no-pager. Pas 5: activar amb systemctl enable --now veloz-vigilant.timer i comprovar amb list-timers. Pas 6: treure la línia de cron —s'oblida constantment, i el resultat és la tasca executant-se dues vegades—: comenta-la en lloc d'esborrar-la, amb la data i el motiu.
- Aplicació: el toolkit sobre systemd
| Unitat | Programació | Persistent |
Per què |
|---|---|---|---|
veloz-informe.timer |
OnCalendar=*-*-* 06:30:00 |
true |
L'informe ha d'existir encara que el servidor arrenqués tard |
veloz-copia.timer |
OnCalendar=*-*-* 03:15:00 |
true |
Una còpia perduda és la pitjor de les fallades |
veloz-vigilant.timer |
OnUnitActiveSec=5min |
(no) | Una comprovació endarrerida no aporta res |
sudo systemctl daemon-reload
sudo systemctl enable --now veloz-{informe,copia,vigilant}.timer
systemctl list-timers 'veloz-*'; journalctl -u veloz-copia --since todayCompara el que has guanyat enfront del crontab de 07-01: l'informe es recupera si el servidor va estar apagat, el vigilant espera la xarxa i no s'encavalca mai, els tres registres es consulten amb la mateixa ordre filtrant per unitat, list-timers mostra l'estat de tot d'un cop d'ull, i systemctl start prova cada tasca en condicions idèntiques a les reals.
Errors Habituals i Consells
- Oblidar
daemon-reload, o activar el.serviceen lloc del.timer. Sense recàrrega, edites la unitat i no passa res; ienable veloz-informe.serviceno programa res, perquè s'activa el temporitzador. Type=simpleen una tasca que acaba. La unitat apareix com a fallida cada vegada que funciona bé. Fes servironeshot.- Redireccions, comodins o camins relatius a
ExecStart. No hi ha shell:>,|i$VARes passen literalment, i un camí relatiu falla sempre. - Deixar la línia de cron després de migrar, o una unitat d'usuari sense
enable-linger. El primer executa la tasca dues vegades; el segon funciona mentre tens sessió i deixa de funcionar en desconnectar. sleepllarg en un servei, oRestart=alwayssobre una fallada real. El primer fa quesystemctl stopacabi enSIGKILL(trosseja l'espera); el segon amaga el problema i omple el journal (fes serviron-failureambStartLimitBurst).- Consell: valida sempre amb
systemd-analyze calendarabans d'instal·lar un horari, i amb--iterations=5per veure les properes cinc execucions. Descobrir al cap d'una setmana que el teu «cada 5 minuts» era «a les 5 del matí» fa mal.
Exercicis
Exercici 1. Escriu el parell .service + .timer per a copia.sh: s'ha d'executar a les 03:15 com a usuari veloz, esperar que els sistemes de fitxers estiguin muntats, recuperar l'execució si el servidor va estar apagat, no trigar més d'una hora, i només poder escriure a /copies i al directori de registres.
Exercici 2. Escriu una funció veloz_estat_timer que rebi el nom d'un temporitzador i retorni 0 si està actiu i la seva última execució va ser correcta, 1 si fa més temps de l'esperat que no s'executa, i 2 si el servei associat està en estat fallit.
Solucions
Solució 1.
# veloz-copia.service
[Unit]
Description=Copia de seguretat diaria de dades i configuracio de Veloz Envios
RequiresMountsFor=/copies /srv/veloz/dades
[Service]
Type=oneshot
User=veloz
Group=veloz
ExecStart=/home/veloz/veloz-ops/bin/copia.sh
TimeoutStartSec=3600
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=read-only
ReadWritePaths=/copies /home/veloz/veloz-ops/logs
# veloz-copia.timer
[Timer]
OnCalendar=*-*-* 03:15:00
Persistent=true
RandomizedDelaySec=300
[Install]
WantedBy=timers.targetRequiresMountsFor= és més precís que un After=local-fs.target genèric: garanteix que aquells punts de muntatge concrets estiguin disponibles, que és el que una còpia necessita —si /copies és un disc extern o un NFS que encara no ha muntat, l'script escriuria al directori buit del sistema local sense adonar-se'n—. I ProtectHome=read-only permet llegir ~/veloz-ops però no escriure-hi: per això ReadWritePaths inclou explícitament el directori de registres.
Solució 2.
# veloz_estat_timer <nom.timer> [hores_maximes]
# Codis: 0 ok | 1 fa massa que no s'executa | 2 el servei ha fallat | 3 no existeix
veloz_estat_timer() {
local timer="${1:?falta el timer}" maxim="${2:-26}" servei="${1%.timer}.service"
systemctl list-timers --all --no-legend "$timer" | grep -q . ||
{ veloz_log_error "$timer no existeix o no esta actiu"; return 3; }
[[ $(systemctl is-failed "$servei") == failed ]] &&
{ veloz_log_error "$servei esta en estat fallit"; return 2; }
local segons ultima=$(systemctl show "$servei" -p ExecMainExitTimestamp --value)
[[ -z $ultima ]] && { veloz_log_warn "$servei no s ha executat mai"; return 1; }
segons=$(( $(date +%s) - $(date -d "$ultima" +%s) ))
(( segons > maxim * 3600 )) &&
{ veloz_log_warn "$timer sense executar-se des de fa $(( segons / 3600 ))h"; return 1; }
veloz_log_info "$timer correcte (ultima execucio fa $(( segons / 60 )) min)"
}La peça interessant és systemctl show -p PROPIETAT --value, que és la manera llegible per màquina de consultar systemd: systemctl status està pensat per a humans i el seu format canvia entre versions, mentre que show retorna el valor pelat i és estable. ExecMainExitTimestamp dona la data en un format que date -d entén, així que la resta en segons des de l'època (04-06) dona directament l'antiguitat. is-failed distingeix la fallada real de «no s'ha executat mai», que mereixen respostes diferents. Aquesta funció és la comprovació que faltava a vigilant.sh (07-04): vigilar que les mateixes tasques programades segueixen funcionant.
Conclusió
systemd gestiona unitats, i a un script de Bash n'hi interessen dues: el .service (com s'executa) i el .timer (quan). Van a /etc/systemd/system/ o, les d'usuari, a ~/.config/systemd/user/ amb loginctl enable-linger per sobreviure al tancament de sessió. Al servei, Type=oneshot per a tasques que acaben i simple per a les que no, ExecStart amb camí absolut i sense construccions de shell, User/Group per no córrer com a root, EnvironmentFile=- per carregar la configuració, TimeoutStartSec com el timeout integrat i StandardOutput=journal per centralitzar el registre. Al temporitzador, OnCalendar per a horaris de rellotge —validable amb systemd-analyze calendar, cosa que cron no ofereix—, la família OnBootSec/OnUnitActiveSec per a intervals relatius que no s'encavalquen per disseny, Persistent=true per recuperar el que s'ha perdut amb el servidor apagat, i RandomizedDelaySec per repartir la càrrega. El dia a dia són sis ordres: daemon-reload després de cada canvi (l'oblit més comú), enable --now sobre el temporitzador i no sobre el servei, start per provar la tasca en condicions idèntiques a les reals, status i journalctl -u per veure què va passar, i list-timers com a substitut molt millorat de crontab -l. Afegeix-hi l'enduriment gairebé de franc de NoNewPrivileges, PrivateTmp, ProtectSystem i ReadWritePaths, i recorda que en un servei de llarga durada Restart=on-failure amb StartLimitBurst no arregla un script mal escrit, i que cal atendre SIGTERM amb un trap i trossejant els sleep. En migrar de cron, sis passos i un que s'oblida sempre: treure la línia del crontab, o la tasca s'executarà dues vegades. Amb això, les quatre tasques del toolkit corren soles, es recuperen d'una aturada, esperen la xarxa i comparteixen registre. Però tot això passa en un sol servidor, i en producció n'hi ha tres —srv-veloz-01, srv-veloz-02 i srv-veloz-03—: comprovar l'estat de la flota entrant a mà a cadascun no és automatització. A 07-06 fem el salt: ssh des del punt de vista d'un script, autenticació per clau i els seus riscos, ~/.ssh/config amb reutilització de connexió, les opcions sense les quals un ssh dins d'un bucle es menja l'entrada estàndard, blocs remots amb here-document, i recorreguts de la flota en paral·lel amb gestió d'errors individual. Neix flota.sh.
Curs de Programació en Bash
Mòdul 1: Introducció a Bash
- Què és Bash?
- Configurar el teu Entorn
- Navegació Bàsica per la Línia d'Ordres
- Entendre el Shell
- Trobar Ajuda: man, help i --help
Mòdul 2: Ordres Bàsiques de Bash
- Operacions amb Fitxers i Directoris
- Ordres de Processament de Text
- Permisos i Propietat dels Fitxers
- Redirecció i Canonades
- Comodins i Expansió de Rutes
- Historial i Dreceres de Teclat
Mòdul 3: Fonaments de Scripting
- Crear i Executar un Script
- Variables i Constants
- Operadors Bàsics
- Sentències Condicionals
- Arguments i Entrada de l'Usuari
- Cometes, Expansió i Substitució
Mòdul 4: Scripting Intermedi
- Bucles en Bash
- Funcions en Bash
- Arrays i Arrays Associatius
- Manipulació de Cadenes
- La Sentència case i els Menús Interactius
- Aritmètica i Càlculs Numèrics
Mòdul 5: Tècniques Avançades de Scripting
- Operacions Avançades amb Fitxers
- Gestió de Processos
- Gestió d'Errors i Depuració
- Expressions Regulars
- Entrada/Sortida Avançada: Descriptors i Here-Documents
- Scripts Modulars i Llibreries Reutilitzables
Mòdul 6: Treballar amb Eines Externes
Mòdul 7: Automatització i Programació
- Tasques Cron
- Automatitzar Tasques
- Scripts de Còpia i Restauració
- Monitoratge i Registre
- Serveis i Temporitzadors amb systemd
- Automatització Remota amb SSH
Mòdul 8: Bones Pràctiques i Optimització
- Escriure Codi Llegible
- Optimitzar Scripts en Bash
- Consideracions de Seguretat
- Control de Versions amb Git
- Anàlisi Estàtica amb ShellCheck i shfmt
- Proves Automatitzades amb Bats
- Portabilitat: POSIX sh enfront de Bashismes
