Arribem a la fita del mòdul, i a una promesa que arrosseguem des de 04-02. informe-diari.sh és avui un programa robust: valida el seu entorn, es protegeix amb flock, avorta amb diagnòstic, valida text amb regex i dirigeix la seva sortida amb precisió. Però és també un únic fitxer de diversos centenars de línies on conviuen log_info, morir, validar_entorn i percentatge —funcions que no tenen res a veure amb informes i que qualsevol altre script del toolkit necessitaria—. La temptació, quan escriguis arxivar-historic.sh la setmana vinent, serà copiar i enganxar. I aquí comença el deteriorament: dues còpies que divergeixen, una fallada corregida en una i no en l'altra, tres convenis de registre diferents. En aquesta lliçó converteixes aquest fitxer en un projecte amb arquitectura.
Contingut
sourceenfront d'executar- Què és una llibreria en Bash
- Localitzar la llibreria sense que les rutes et traeixin
- Guardes d'inclusió
- Noms: què és públic i què és privat
- Fitxers de configuració
- Ordre de precedència
- L'estructura final del toolkit
lib/comu.shinforme-diari.shcom a orquestrador- Provar la llibreria a mà
source enfront d'executar
source enfront d'executarA 03-01 vas veure les formes d'executar un script. La que ara importa és la que no crea un procés: enfront de ./script.sh o bash script.sh, que llancen un procés nou del qual no torna res, source script.sh (o la seva forma POSIX . script.sh) executa el fitxer en aquest shell.
| Executar | source |
|
|---|---|---|
| Procés | Un de nou (fork + exec) | L'actual |
| Variables i funcions que defineix | Moren amb el fill | Queden disponibles |
cd que faci |
No t'afecta | Et canvia de directori |
Necessita permís +x i shebang |
Sí | No |
exit a dins |
Acaba l'script | Acaba el teu shell |
Les dues últimes files expliquen per què una llibreria no és un script normal. Com que es carrega amb source, no necessita ni shebang executable ni permís d'execució. I sobretot: un exit en una llibreria mata qui la carrega, inclosa la teva sessió interactiva si l'estaves provant; dins d'una llibreria es fa servir return. Això no és nou: és el mateix mecanisme pel qual ~/.bashrc defineix funcions que el teu shell coneix (01-02). Una llibreria és un .bashrc per als teus scripts.
- Què és una llibreria en Bash
Una llibreria és un fitxer que conté només definicions: funcions, constants i, com a molt, valors per defecte. Res que actuï per si mateix.
# lib/comu.sh — CORRECTE: només defineix
log_info() { printf '%s [INFO] %s\n' "$(date '+%F %T')" "$*" >&2; }
# lib/dolent.sh — INCORRECTE: tot això ACTUA en carregar-se
log_info "carregant llibreria" # embruta la sortida de qui la faci servir
set -euo pipefail # IMPOSA la seva política a qui la carrega
cd /srv/veloz # canvia el directori de qui la carregaLa regla és que carregar la llibreria ha de ser silenciós i sense efectes. El set -euo pipefail dins d'una llibreria és especialment traïdor: en fer source s'aplica al shell que la carrega, així que pot canviar el comportament d'errors d'un script que no s'ho esperava. La política estricta la decideix l'executable, no la llibreria. Convencions: extensió .sh (o .bash), sense shebang executable —opcionalment un #!/usr/bin/env bash com a pista per a editors i per a shellcheck, però sense permís +x—, i una capçalera de comentari que digui què ofereix.
- Localitzar la llibreria sense que les rutes et traeixin
Aquí hi ha el problema tècnic de debò. Com troba bin/informe-diari.sh la lib/comu.sh?
source lib/comu.sh # MALAMENT: relatiu al directori ACTUAL, no a l'script
source ~/veloz-ops/lib/comu.sh # Funciona, però només per a tu i al teu $HOMELes rutes relatives es resolen des del directori de treball actual, que és on sigui qui llança l'script, no on viu l'script. Com que ~/veloz-ops/bin és al PATH (el vam posar allà a 01-02), el normal és invocar-lo des de qualsevol lloc, i el source falla. L'idioma canònic és aquest:
BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"; readonly BASE_DIR
source "$BASE_DIR/lib/comu.sh"Desmuntat de dins cap a fora:
${BASH_SOURCE[0]}és la ruta del fitxer en execució. Es fa servir en comptes de$0per dos motius:$0valbashquan l'script s'invoca com abash script.sh, i dins d'un fitxer carregat ambsource,$0segueix sent el de l'script principal mentre queBASH_SOURCE[0]és la llibreria. Per a una llibreria que necessita saber on és,$0dona sempre la resposta equivocada.dirnamedona el directori que la conté (04-04) i/..puja a l'arrel del projecte;cd ... && pwdconverteix aquesta ruta, que pot ser relativa (./bin/..), en absoluta i normalitzada; i tot va entre cometes, per si la ruta conté un espai.
Amb això, l'script funciona invocat com a ./bin/informe-diari.sh, com a ~/veloz-ops/bin/informe-diari.sh, des del PATH o des de cron amb qualsevol directori de treball. Si a més vols seguir enllaços simbòlics fins al fitxer real, readlink -f (05-01) sobre ${BASH_SOURCE[0]} abans del dirname ho resol.
- Guardes d'inclusió
Si informe-diari.sh carrega comu.sh i també informe.sh, que al seu torn carrega comu.sh, el fitxer es processa dues vegades. Redefinir funcions és inofensiu, però un readonly duplicat provoca un error fatal sota mode estricte (VELOZ_VERSION: variable de només lectura). La solució és la mateixa idea que els include guards de C:
El return 0 a nivell superior d'un fitxer carregat amb source és legal i significa «acaba de llegir aquest fitxer». El :- és obligatori perquè l'script que la carrega té set -u (05-03) i la variable encara no existeix la primera vegada. El guionet baix inicial marca la variable com a interna.
- Noms: què és públic i què és privat
Bash no té espais de noms: tot viu en un únic àmbit global. Si la teva llibreria defineix log() i la del company també, l'última carregada guanya silenciosament. El remei és un prefix:
veloz::log_info() { ... } # estil amb dos punts dobles
veloz_log_info() { ... } # estil amb guionet baix, més portable
_veloz_normalitza() { ... } # guionet baix inicial: ús INTERN, no la cridisBash permet :: en noms de funció i queda molt llegible, però no és POSIX i algunes eines antigues s'hi ennueguen; veloz_ és l'opció segura. Tria'n un i sigues consistent. La distinció públic/privat és per conveni, no la imposa l'intèrpret: el guionet baix inicial és una promesa de «això pot canviar sense avís, no en depenguis». El que sí que pots controlar de debò és l'àmbit de les variables: tota variable dins d'una funció va amb local (04-02), i així no contamina l'script que la faci servir.
- Fitxers de configuració
~/veloz-ops/etc/veloz-ops.conf existeix des del principi del curs amb permisos 600. La seva forma més simple és un fitxer d'assignacions (VELOZ_CSV=/srv/veloz/dades/enviaments.csv, VELOZ_LOG_NIVELL=info, VELOZ_CIUTATS="Valencia Sevilla Bilbao Madrid") que es carrega amb [[ -r "$BASE_DIR/etc/veloz-ops.conf" ]] && source "$BASE_DIR/etc/veloz-ops.conf". És còmode —admet comentaris, cometes, fins i tot $(...)— i té un risc que has de conèixer: source executa codi arbitrari. Una línia rm -rf ~ en aquest fitxer s'executa amb els teus permisos. Per això els 600 no són decoratius: si algú pot escriure al teu fitxer de configuració, pot executar el que vulgui com tu. Les implicacions completes es tracten a 08-03.
L'alternativa segura és analitzar clau=valor sense executar res, fent servir el que has après a 05-04:
# _veloz_carrega_conf — Carrega clau=valor sense executar codi. Ús: ... <fitxer>
_veloz_carrega_conf() {
local fitxer="${1:?}" clau valor linia
[[ -r "$fitxer" ]] || return 0
while IFS= read -r linia; do
[[ "$linia" =~ ^[[:space:]]*([A-Za-z_][A-Za-z0-9_]*)=(.*)$ ]] || continue
clau="${BASH_REMATCH[1]}"; [[ "$clau" == VELOZ_* ]] || continue # només el nostre
valor="${BASH_REMATCH[2]}"; valor="${valor%\"}"; valor="${valor#\"}"
printf -v "$clau" '%s' "$valor" # assignació indirecta
done < "$fitxer"
}Aquí es troben tres mòduls: la regex amb BASH_REMATCH de 05-04 (que a més descarta comentaris i línies buides en no encaixar), les expansions ${v%\"} de 04-04 i el bucle while read de 04-01. El filtre VELOZ_* impedeix que el fitxer redefineixi PATH o HOME, i printf -v assigna a la variable el nom de la qual és a $clau: la manera segura de fer assignació indirecta sense eval.
- Ordre de precedència
Tanquem aquí el disseny d'opcions començat a 03-05. Quan el mateix valor pot venir de quatre llocs, cal un ordre explícit i documentat, de menor a major prioritat:
| Nivell | Origen | Exemple | Guanya sobre |
|---|---|---|---|
| 1 | Valor per defecte al codi | VELOZ_CSV=/srv/veloz/dades/enviaments.csv |
Res |
| 2 | Fitxer de configuració | etc/veloz-ops.conf |
El defecte |
| 3 | Variable d'entorn | VELOZ_CSV=/tmp/x.csv informe-diari.sh |
Els anteriors |
| 4 | Opció de línia d'ordres | --csv /tmp/x.csv |
Tots |
El principi: com més a prop de l'usuari i del moment de l'execució, més prioritat. Implementar-ho és senzill si respectes l'ordre de càrrega, i : "${VAR:=valor}" és l'idioma per a «assigna només si és buida o no definida» —el := assigna, a diferència del :- que només substitueix, i el : inicial és l'ordre nul·la—, de manera que una variable d'entorn ja definida sobreviu:
: "${VELOZ_CSV:=/srv/veloz/dades/enviaments.csv}" # 1. defecte, només si no existeix
_veloz_carrega_conf "$BASE_DIR/etc/veloz-ops.conf" # 2. config (respecta el ja definit)
# 3. l'entorn ja estava posat abans d'arrencar l'script
while [[ $# -gt 0 ]]; do case "$1" in # 4. opcions (03-05)
--csv) VELOZ_CSV="$2"; shift 2 ;; *) break ;;
esac; done
- L'estructura final del toolkit
~/veloz-ops/ ├── bin/ # executables (+x, amb shebang). Són al PATH │ ├── informe-diari.sh │ └── arxivar-historic.sh ├── lib/ # llibreries (sense +x, sense shebang, només definicions) │ ├── comu.sh # registre, errors, validacions, utilitats │ └── informe.sh # lògica específica d'informes ├── etc/veloz-ops.conf # configuració (permisos 600) └── logs/ # sortida: informes, traces, fitxers de bloqueig
La regla de repartiment en una frase: a bin/ va el que s'invoca, a lib/ el que es reutilitza, a etc/ el que canvia entre màquines i a logs/ el que es genera. És la mateixa lògica de l'FHS que vas veure a 01-03, aplicada a escala de projecte, i per això resulta familiar a qualsevol que obri el repositori. Un criteri pràctic per decidir on va una funció: si la necessitaria un script que no tingués res a veure amb informes, va a comu.sh; si només té sentit parlant d'enviaments i ciutats, va a informe.sh.
lib/comu.sh
lib/comu.sh#!/usr/bin/env bash
# comu.sh — Utilitats compartides del toolkit de Veloz Envíos.
# Carregar amb: source "$BASE_DIR/lib/comu.sh"
[[ -n "${_COMU_SH:-}" ]] && return 0
readonly _COMU_SH=1 VELOZ_VERSION='1.0'
readonly _VELOZ_RE_DATA='^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$'
# veloz_log_info — Missatge informatiu a stderr. Ús: veloz_log_info <text...>
veloz_log_info() {
[[ "${VELOZ_LOG_NIVELL:-info}" == silencios ]] && return 0
printf '%s [INFO] %s\n' "$(date '+%F %T')" "$*" >&2
}
# veloz_log_error — Missatge d'error a stderr. Ús: veloz_log_error <text...>
veloz_log_error() { printf '%s [ERROR] %s\n' "$(date '+%F %T')" "$*" >&2; }
# veloz_morir — Error fatal i sortida. Ús: veloz_morir <codi> <text...>
veloz_morir() { local c="${1:?}"; shift; veloz_log_error "$*"; exit "$c"; }
# veloz_validar_data — És AAAA-MM-DD i existeix? Ús: veloz_validar_data <data>
veloz_validar_data() { [[ "${1:-}" =~ $_VELOZ_RE_DATA ]] && date -d "$1" &>/dev/null; }
# veloz_percentatge — Calcula a/b*100 amb 2 decimals. Ús: veloz_percentatge <a> <b>
veloz_percentatge() {
(( ${2:?} == 0 )) && { printf '0.00\n'; return 0; }
bc -l <<< "scale=2; ${1:?} * 100 / $2"
}
# veloz_validar_entorn — Comprova dependències i rutes. Ús: veloz_validar_entorn
veloz_validar_entorn() {
local cmd
for cmd in bc date find flock; do
command -v "$cmd" > /dev/null || veloz_morir 69 "Falta la utilitat: $cmd"
done
[[ -r "${VELOZ_CSV:?sense definir}" ]] || veloz_morir 66 "No puc llegir $VELOZ_CSV"
mkdir -p "${VELOZ_LOG_DIR:?}" || veloz_morir 73 "No puc crear $VELOZ_LOG_DIR"
}Fixa't en el que no hi ha: ni set -euo pipefail, ni shebang executable, ni una sola línia que actuï en carregar-se més enllà de la guarda i les constants. veloz_morir és l'única que crida exit, i és correcte perquè està pensada per fer-se servir des d'un executable, no des d'una sessió interactiva.
informe-diari.sh com a orquestrador
informe-diari.sh com a orquestrador#!/usr/bin/env bash
# informe-diari.sh — Informe diari de repartiment de Veloz Envíos.
set -Eeuo pipefail
BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"; readonly BASE_DIR
source "$BASE_DIR/lib/comu.sh"
source "$BASE_DIR/lib/informe.sh"
: "${VELOZ_CSV:=/srv/veloz/dades/enviaments.csv}"
: "${VELOZ_LOG_DIR:=$BASE_DIR/logs}"
_veloz_carrega_conf "$BASE_DIR/etc/veloz-ops.conf"
main() {
local data subordre; data=$(date +%F)
while [[ $# -gt 0 ]]; do case "$1" in # el bucle d'opcions de 03-05
--data) veloz_validar_data "${2:-}" || veloz_morir 64 "Data invàlida: ${2:-}"
data="$2"; shift 2 ;;
--debug) activar_debug; shift ;;
-h|--help) us; exit 0 ;;
*) break ;;
esac; done
subordre="${1:-resum}"
exec 9> "$VELOZ_LOG_DIR/.informe.lock"
flock -n 9 || veloz_morir 75 "Ja hi ha un informe en curs"
TREBALL=$(mktemp -d); readonly TREBALL
trap 'rm -rf "$TREBALL"' EXIT INT TERM
veloz_validar_entorn
acumular_dia "$data"
case "$subordre" in
resum) generar_informe "$data" "$VELOZ_LOG_DIR/informe-$data.txt" ;;
detall) taula_detall "$data" ;;
ciutats) taula_ciutats ;;
*) veloz_morir 64 "Subordre desconeguda: $subordre" ;;
esac
}
main "$@"Aquest és el resultat de cinc mòduls. L'executable ja no implementa gairebé res: localitza la seva base, carrega les seves llibreries, resol la configuració, processa opcions, es protegeix amb flock i un trap, i despatxa. Tota la lògica reutilitzable viu a lib/. Quan escriguis arxivar-historic.sh, les tres primeres línies seran idèntiques i tindràs de franc el registre, els errors i les validacions.
- Provar la llibreria a mà
Una llibreria ben feta es pot carregar en una sessió interactiva, i això és el que la fa verificable:
$ source ~/veloz-ops/lib/comu.sh
$ veloz_percentatge 11 128 # 8.59
$ veloz_validar_data 2026-02-31 && echo ok || echo malament # malament
$ declare -F | grep veloz # totes les funcions definides
$ type veloz_percentatge # veure el codi d'una funciódeclare -F llista els noms de les funcions definides i type mostra el cos (01-04). Si en fer source apareix qualsevol sortida, hi ha codi de nivell superior que hi sobra. Per a proves automàtiques de debò —afirmacions, casos límit, informe de resultats— l'eina és bats, a 08-06. I shellcheck -x segueix els source per analitzar també les llibreries, a 08-05.
Errors Habituals i Consells
source lib/comu.shamb ruta relativa. Funciona al teu directori i falla des decrono elPATH.- Fer servir
$0per localitzar l'script. Donabashambbash script.shi el fitxer equivocat dins d'una llibreria. Fes servir${BASH_SOURCE[0]}. exitdins d'una llibreria carregada al teu shell. Tanca el teu terminal. Fes servirreturn.- Codi de nivell superior a la llibreria, i en especial un
set -euo pipefail: embruta la sortida i imposa la seva política a l'script que la carrega, potser sense que s'ho esperi. readonlysense guarda d'inclusió, que en carregar-se dues vegades dona error fatal, i funcions senselocal, que esclafen variables de l'script que les crida setmanes després.- Consell: documenta cada funció amb una línia
# nom — què fa. Ús: nom <args>just a sobre. És el que llegiràs d'aquí a sis mesos, i el que permet generar l'ajuda del toolkit amb un simplegrep '^# [a-z]' lib/*.sh.
Exercicis
Exercici 1. Escriu la capçalera completa d'arxivar-historic.sh (a bin/) que localitzi BASE_DIR de manera robusta, carregui lib/comu.sh, apliqui mode estricte i falli amb un missatge clar si la llibreria no és on hauria de ser.
Exercici 2. Afegeix a comu.sh una funció veloz_config que retorni el valor d'una clau de configuració respectant l'ordre de precedència (defecte < fitxer < entorn), amb guarda d'inclusió i sense fer servir eval.
Exercici 3. Divideix el toolkit: decideix per a cadascuna d'aquestes funcions si va a comu.sh, a informe.sh o al mateix executable, i justifica-ho: veloz_log_info, taula_ciutats, veloz_percentatge, acumular_dia, us, veloz_validar_data.
Solucions
Solució 1.
#!/usr/bin/env bash
# arxivar-historic.sh — Arxiva l'històric mensual de Veloz Envíos.
set -Eeuo pipefail
BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" || exit 78
readonly BASE_DIR LIB="$BASE_DIR/lib/comu.sh"
[[ -r "$LIB" ]] || { printf 'Falta la llibreria %s\n' "$LIB" >&2; exit 78; }
source "$LIB"La comprovació prèvia al source importa: sense ella, el missatge seria source: lib/comu.sh: No such file or directory, que no diu on s'ha buscat. El codi 78 (EX_CONFIG, de la taula de 05-03) és l'adequat: la instal·lació està malament, no les dades. I el missatge fa servir printf directe perquè veloz_log_error encara no existeix.
Solució 2.
# veloz_config — Retorna el valor d'una clau. Ús: veloz_config <CLAU> [defecte]
veloz_config() {
local clau="${1:?}" defecte="${2:-}" valor l
valor="${!clau:-}" # 1) és a l'entorn o ja carregada?
if [[ -z "$valor" && -r "${VELOZ_CONF:-}" ]]; then
while IFS= read -r l; do # 2) buscar al fitxer
[[ "$l" =~ ^[[:space:]]*"$clau"=\"?([^\"]*)\"?$ ]] || continue
valor="${BASH_REMATCH[1]}"; break
done < "$VELOZ_CONF"
fi
printf '%s\n' "${valor:-$defecte}" # 3) defecte com a últim recurs
}${!clau} és l'expansió indirecta: obté el valor de la variable el nom de la qual és a $clau. És la lectura equivalent al printf -v de la secció 6, i totes dues eviten eval, que executaria el contingut del fitxer de configuració —justament el risc del qual fugim—. L'ordre de les tres branques és la taula de precedència.
Solució 3.
| Funció | Destí | Motiu |
|---|---|---|
veloz_log_info, veloz_percentatge, veloz_validar_data |
lib/comu.sh |
Registre, aritmètica i validació genèrics: no saben res d'enviaments |
acumular_dia, taula_ciutats |
lib/informe.sh |
Coneixen el format del CSV, els estats d'enviament i la seva presentació |
us |
L'executable | Cada script té les seves pròpies opcions; no és reutilitzable |
El criteri és una sola pregunta: ho necessitaria un script que no parli d'enviaments? Si la resposta és sí, va a comu.sh. us és el cas interessant: encara que tots els scripts en tinguin una, el seu contingut és diferent a cadascun, així que el que es pot compartir no és la funció sinó el conveni que existeixi.
Conclusió
source executa un fitxer al shell actual, i d'aquí en surt tota la resta: les funcions i variables que defineix queden disponibles, no cal shebang ni permís d'execució, i un exit mataria qui la carrega —dins d'una llibreria es fa servir return—. Una llibreria conté només definicions, sense codi que actuï, sense set -euo pipefail que imposi polítiques alienes i sense missatges en carregar-se. Es localitza amb BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)", mai amb $0 ni amb rutes relatives, perquè un script s'invoca des de qualsevol directori i des del PATH. Una guarda [[ -n ${_COMU_SH:-} ]] && return 0 evita la doble càrrega i l'error dels readonly duplicats, i un prefix veloz_ substitueix els espais de noms que Bash no té, amb el guionet baix inicial marcant el que és privat. La configuració viu a etc/veloz-ops.conf amb permisos 600 —perquè carregar-lo amb source executa el que contingui— o s'analitza com a clau=valor amb BASH_REMATCH i printf -v, i resol els seus conflictes amb una precedència explícita: defecte < fitxer < entorn < línia d'ordres. El resultat és ~/veloz-ops/ amb bin/, lib/, etc/ i logs/, i un informe-diari.sh que ja no implementa: orquestra.
Amb això es tanca el Mòdul 5, i amb ell la part del curs dedicada al que Bash sap fer per si mateix. El toolkit de Veloz Envíos és avui robust, segur amb els seus fitxers i processos, capaç de diagnosticar les seves pròpies fallades, precís en validar text, amo de la seva entrada i sortida, i modular. Però continua sent maldestre en un terreny concret: cada vegada que cal fer comptes per columnes sobre el CSV, encadena cut, sort, uniq i bucles que llegeixen el fitxer diverses vegades; cada vegada que cal reescriure text, falten eines; i quan la veloz-api deixi de ser un procés que es comprova amb pgrep i passi a ser una API que cal consultar, Bash sol no hi arriba.
Al Mòdul 6 entren les eines externes que multipliquen el que Bash sap fer: awk, que processa columnes i agrega en una sola passada el que avui et costa vint línies (06-01); sed, per transformar text en flux amb les regex que ja domines (06-02); les ordres per interrogar el sistema —disc, memòria, usuaris, maquinari— (06-03); les eines de xarxa i el /dev/tcp que vam deixar apuntat (06-04); i curl amb jq per parlar amb la veloz-api i manejar JSON de debò, que és on el teu toolkit deixarà de llegir fitxers per començar a integrar-se amb la resta del sistema (06-05).
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
