Navegant per la xarxa nacional em vaig trobar amb un interessant article (El qual porto cap aquí textualment perquè està magistralment explicat) on el seu autor ens mostra com fer que els nostres scripts de Bash siguin més robustos usant Trampes.
Feu scripts de bash més robustos amb traps
Imagina que tens un script de bash que s'executi cada dia cada sis hores i que en algun moment falli o que aquest mateix script s'executi dues vegades simultàniament. Aquestes dues situacions són força incòmodes ja que requereixen de la intervenció humana per a ser corregides o en certs moments no poden ser ateses deixant el sistema en un estat inconsistent. La solució a això, entre altres és usar traps.
Traps és una manera senzilla i efectiva de controlar la sortida dels scripts de bash. Tornem a la mateixa situació inicial, si l'script és detingut manualment, per exemple amb ctrl-c, s'interromp retornant el senyal de sortida
INT
i si s'acaba amb
kill
llavors la sortida seria
TERM
.
Tots els codis de sortida possibles es poden veure amb
kill -l
però els més utilitzats són precisament
INT, TERM, EXIT
Si l'script consisteix, per exemple, en la sincronització d'arxius amb
rsync
el més assenyat és recolzar-se en un arxiu lock que no permeti que l'script s'executi simultàniament:
LOCK = "/ var / run / rsync.lock" if [! -i $ LOCK]; then touch $ LOCK rsync -avz foo bar rm $ LOCK else echo "rsync ja s'està executant" fi
En espanyol pla, l'script anterior comprova si existeix el fitxer lock i si aquest no existeix el crea i posteriorment executa la comanda corresponent, finalment elimina l'arxiu lock. Si existeix l'arxiu l'script simplement envia un missatge a l'usuari indicant-li que ja la comanda s'està executant.
No obstant això quan una hi ha una situació problemàtica pogués passar que l'arxiu bloqueig de taula no s'elimini donant a l'trast amb efectes indesitjats. La solució és ben senzilla:
LOCK = "/ var / run / rsync.lock" if [! -i $ LOCK]; then trap "rm -f $ LOCK; exit" INT TERM EXIT touch $ LOCK rsync -avz foo bar rm $ LOCK trap - INT TERM EXIT else echo "rsync ja s'està executant" fi
La particularitat d'aquesta solució és que la comanda està tancat en un trap, de manera que quan es rep un senyal
INT, TERM, EXIT
l'script es deté i esborra l'arxiu lock.
Val la pena dir que pogués donar-se una situació de competència en l'script anterior entre el temps en què es verifica l'arxiu lock i el temps en què aquest es crea. Una possible solució seria utilitzar una redirecció i la manera noclobber de bash que no redirigeix a un arxiu existent:
LOCK = "/ var / run / rsync.lock" if (set -o noclobber; echo $$> "$ LOCK") 2> / dev / null; then trap 'rm -f "$ LOCK"; exit $? ' INT TERM EXIT rsync -avz foo bar rm -f $ LOCK trap - INT TERM EXIT else echo "rsync ja s'està executant: $ (cat $ Lck)" fi
La particularitat d'aquest últim és que s'usa com ja havia dit, la manera noclobber i que l'arxiu lock conté el PID de el procés que s'executa.
També val la pena esmentar que hi ha altres solucions com
flock
o
solo
no obstant això en aquesta entrada vaig voler compartir les solucions amb recursos propis de bash. Poden aprendre una mica més sobre Traps amb aquesta excel·lent guia.
Genial! Gràcies per compartir.
Bon article, només canviar 'trobo «rsync ja s'està executant: $ (cat $ Lck)»' per 'trobo «rsync ja s'està executant: $ (cat $ LOCK)»'
Salutacions
Un article molt interessant, sí senyor! Aquest me'l guardo.
És una ordre molt útil per tenir en compte. Jo el vaig fer servir en un script que vaig publicar en un post, per esborrar alguns arxius que creava l'script quan aquest era detingut.
Molt interessant, si senyor.