Tot el curs ha donat per suposada una cosa: que l'intèrpret és Bash 5 sobre Ubuntu 24.04. És una suposició raonable per a srv-veloz-01/02/03, i per això hem fet servir arrays associatius, mapfile, [[ ]], ${s^^} i set -o pipefail sense pensar-ho dues vegades. Però el dia que calgui escriure l'entrypoint.sh del contenidor Alpine de la veloz-api, o un script d'arrencada que corre abans que Bash estigui disponible, o una eina que un company executarà al seu macOS, aquesta suposició es trenca i l'script falla amb errors desconcertants. Aquesta lliçó explica què és POSIX, quines construccions nostres són bashismes, quins són els seus equivalents, per què les eines externes donen més problemes que el mateix shell, com comprovar la portabilitat i —el més important— quan val la pena i quan és un llast.
Contingut
- Què és POSIX i què és un bashisme
- L'escenari real: qui és
/bin/sha cada sistema - Taula de bashismes i el seu equivalent POSIX
- Detalls que cal conèixer en baixar a POSIX
- Les eines externes fan més mal que el shell
- Com comprovar la portabilitat
- La decisió de disseny, amb criteri explícit per a Veloz Envíos
- Declarar la dependència: comprovar
BASH_VERSINFO - Què aporta cada versió de Bash i el problema de macOS
- Balanç del mòdul 8
- Què és POSIX i què és un bashisme
POSIX és un estàndard (IEEE 1003.1) que defineix, entre moltes altres coses, el llenguatge del shell: quina sintaxi ha d'entendre qualsevol shell que es declari conforme. És el mínim comú denominador, i és deliberadament auster: no té arrays, ni [[ ]], ni substitució de cadenes a les expansions.
Un bashisme és qualsevol construcció que Bash entén i l'estàndard no exigeix. No són errors —són les raons per les quals Bash és còmode—, però només funcionen on hi ha Bash. El problema sorgeix per una confusió concreta: escriure #!/bin/sh a la primera línia i fer servir sintaxi de Bash a dins. A Ubuntu, si a més el proves executant bash script.sh, funciona; al contenidor Alpine, on /bin/sh és un altre programa, falla.
- L'escenari real: qui és
/bin/sh a cada sistema
/bin/sh a cada sistema| Sistema | /bin/sh és |
Conseqüència |
|---|---|---|
| Debian / Ubuntu | dash |
Ràpid i estricte: cap bashisme no funciona |
| Alpine (contenidors) | ash (BusyBox) |
Encara més reduït; a més, les eines són BusyBox |
| RHEL / Fedora | bash en mode POSIX |
Molts bashismes «funcionen»: falsa sensació de seguretat |
| macOS | bash 3.2 o zsh |
Bash antic: sense arrays associatius ni mapfile |
| FreeBSD / Solaris | sh propi, ksh |
Diferències en els detalls |
Les dues files perilloses són la de RHEL i la de macOS, per motius oposats. A RHEL el teu script amb bashismes i #!/bin/sh funciona, així que ningú no detecta el problema fins que arriba a Debian. A macOS l'intèrpret es diu bash però és la versió 3.2 del 2006 —Apple no l'actualitza per motius de llicència—, així que un script perfectament correcte per a Bash 5 falla amb missatges críptics.
L'error típic es veu així:
[[: not found és la signatura inconfusible d'un bashisme a dash: no és un error de sintaxi, és que dash busca una ordre anomenada [[.
- Taula de bashismes i el seu equivalent POSIX
| Bashisme | Equivalent POSIX | Nota |
|---|---|---|
[[ $a == $b ]] |
[ "$a" = "$b" ] |
En POSIX les cometes són obligatòries |
[[ $s == a* ]] |
case $s in a*) ;; esac |
POSIX no té comparació amb patró a [ ] |
[[ $s =~ regex ]] |
expr "$s" : 'regex' o grep -q |
Sense BASH_REMATCH; el més dolorós |
arr=(a b c), ${arr[@]} |
Paràmetres posicionals: set -- a b c, "$@" |
Un sol «array» per àmbit |
declare -A |
No existeix | Sense arrays associatius: fitxer temporal o awk |
${s//a/b} |
printf '%s' "$s" | sed 's/a/b/g' |
Costa un procés |
${s^^} / ${s,,} |
tr '[:lower:]' '[:upper:]' |
Ídem |
${s:0:3} |
printf '%s' "$s" | cut -c1-3 |
${s#...} i ${s%...} sí que són POSIX |
$(( a + b )) |
$(( a + b )) |
Sí que és POSIX, fes-lo servir sense por |
(( i++ )) |
i=$(( i + 1 )) |
L'ordre (( )) no és POSIX |
local x |
(no és a l'estàndard) | L'implementen dash, ash i ksh: segur a la pràctica |
function f { }, source f |
f() { }, . f |
La forma amb parèntesis i el punt són les portables |
echo -e "a\tb" |
printf 'a\tb\n' |
echo amb opcions no és portable |
<<< "$cadena" |
<<EOF … EOF o printf ... | |
El here-string és de Bash |
<(cmd) |
Fitxer temporal amb mktemp |
Substitució de procés: sense equivalent |
arr+=(x), s+=text |
s="${s}text" |
L'operador += no és POSIX |
${BASH_SOURCE[0]}, read -a, mapfile |
$0; while read + set -- |
Sense arrays no hi ha equivalent directe |
set -o pipefail, trap ... ERR |
No existeixen | Vegeu l'apartat 4; només trap ... EXIT INT TERM |
{1..10} |
seq 1 10 o while |
L'expansió de claus no és POSIX |
&> fitxer |
> fitxer 2>&1 |
Molt fàcil d'oblidar |
- Detalls que cal conèixer en baixar a POSIX
[ ] no és [[ ]]. És una ordre, no sintaxi, així que els seus arguments pateixen divisió en paraules. [ $a = $b ] amb $a buida es converteix en [ = valor ] i dóna un error de sintaxi. Amb cometes —[ "$a" = "$b" ]— funciona sempre. Fes servir =, no ==, i -a/-o estan obsolets: encadena amb && i || entre dos [ ].
Sense pipefail. És la pèrdua més seriosa, perquè cmd1 | cmd2 retorna el codi de cmd2 i una fallada del primer passa inadvertida (05-03). La sortida practicable és trencar la canonada: escriure la primera etapa en un temporal amb mktemp, comprovar-ne el codi de sortida i llegir el temporal a la segona. A la pràctica, un script POSIX es reestructura per no encadenar ordres la fallada de les quals importi.
Sense arrays. El substitut són els paràmetres posicionals:
set -- Valencia Sevilla Bilbao Madrid # "array" de 4 elements
for ciutat in "$@"; do printf 'processant %s\n' "$ciutat"; done
printf 'total: %d\n' "$#"És un únic conjunt per àmbit, així que si necessites dues llistes alhora, o en guardes una en una funció o passes a awk.
Sense local, en teoria. L'estàndard no l'inclou, però dash, ash, ksh i zsh l'implementen. La recomanació pràctica: fes-lo servir, i documenta a la capçalera que l'script requereix un shell amb local.
- Les eines externes fan més mal que el shell
Aquesta és la part que gairebé tothom subestima. Pots escriure un script POSIX impecable i que falli a macOS perquè sed -i funciona diferent. Linux fa servir GNU coreutils; macOS i els BSD fan servir les eines BSD; Alpine fa servir BusyBox, que és una tercera implementació reduïda.
| Ús | GNU (Linux) | BSD / macOS | Portable |
|---|---|---|---|
| Editar al lloc | sed -i 's/a/b/' f |
sed -i '' 's/a/b/' f |
sed 's/a/b/' f > t && mv t f |
| Data relativa | date -d '3 days ago' |
date -v-3d |
Calcular amb $(( )) sobre date +%s |
| Data des de l'època | date -d "@$s" |
date -r "$s" |
Cap: detectar la variant |
| Camí absolut | readlink -f |
No existeix (fes servir realpath o stat) |
cd "$(dirname "$f")" && pwd |
| Regex Perl | grep -P '\d+' |
No suportat | grep -E '[0-9]+' |
| Mida de fitxer | stat -c %s f |
stat -f %z f |
wc -c < f |
| Sense entrada, no executar | xargs -r |
Comportament per defecte | xargs -r només a GNU/BusyBox |
| Format a find | find . -printf '%s\n' |
No existeix | find . -exec stat ... \; |
Tres estratègies, en ordre de preferència:
- Cenyir-se a les opcions POSIX de cada eina.
sed 's/a/b/'sense-i,grep -E,find -exec. És el més robust i gairebé sempre suficient. - Detectar la variant en arrencar i adaptar-s'hi:
if date -d '@0' >/dev/null 2>&1
then data_de_epoca() { date -d "@$1" +%F; } # GNU
else data_de_epoca() { date -r "$1" +%F; } # BSD
fi- Declarar la dependència: exigir
coreutilsi comprovar-ho ambveloz_requereix(06-03). A macOS s'instal·len ambbrew install coreutils, encara que queden amb prefixg(gsed,gdate).
- Com comprovar la portabilitat
Tres eines complementàries, més una prova real:
$ checkbashisms entrypoint.sh # paquet devscripts
possible bashism in entrypoint.sh line 14 (should be '.', not 'source'):
source /etc/veloz/env.sh
possible bashism in entrypoint.sh line 22 ([[ ... ]]):
if [[ -z "$VELOZ_API_URL" ]]; then
$ shellcheck -s sh entrypoint.sh # 08-05, dialecte POSIX
In entrypoint.sh line 22:
^-- SC2039 (warning): In POSIX sh, [[ ]] is undefined.
$ dash -n entrypoint.sh # nomes sintaxi, pero es l'interpret real
$ dash entrypoint.sh # execucio real: el mes fiablecheckbashisms és l'especialista i detecta coses que ShellCheck no marca; shellcheck -s sh s'integra amb la resta del flux i explica el perquè; dash -n valida la sintaxi amb l'intèrpret que realment es farà servir a Debian. Però la comprovació definitiva és executar-lo on ha de córrer:
Allà es descobreixen alhora els bashismes i les diferències de BusyBox, que són la meitat del problema. Mereix una feina de CI (08-05) al costat de la de ShellCheck.
- La decisió de disseny, amb criteri explícit per a Veloz Envíos
POSIX pur no és «millor»: és una restricció que es paga en llegibilitat i en processos. Un ${s^^} es converteix en un tr amb el seu fork, i un array associatiu que resolia una agregació en deu línies es converteix en un fitxer temporal ordenat. Escriure en POSIX el que sempre correrà a Ubuntu és pagar un cost sense comprar res.
| Val la pena POSIX | És un llast |
|---|---|
entrypoint.sh d'un contenidor mínim sense Bash |
Eines internes d'un parc homogeni |
Scripts d'arrencada i initramfs |
Scripts amb lògica de dades i agregació |
| Instal·ladors que s'executen en sistemes desconeguts | Automatització amb arrays i expressions regulars |
Fragments que altres incrusten al seu /bin/sh |
Tot el que ja funciona en Bash 5 |
Criteri per al toolkit, escrit i aplicat:
lib/comu.shi els cinc scripts debin/continuen sent Bash 5, amb#!/usr/bin/env bash, arrays associatius,[[ ]],mapfileiset -euo pipefail. Corren en tres servidors idèntics que administrem nosaltres; renunciar a aquestes eines empitjoraria el codi sense cap guany.- L'
entrypoint.shdel contenidor de laveloz-apis'escriu en POSIX pur amb#!/bin/sh. La imatge base és Alpine, no porta Bash, i afegir-lo només per a l'arrencada significa augmentar la imatge i la seva superfície d'atac. L'script és curt —comprova variables d'entorn, espera la base de dades i faexecdel servei—, justament el tipus de lògica que POSIX cobreix sense esforç.
#!/bin/sh
# entrypoint.sh - arrencada de veloz-api. POSIX pur: la imatge Alpine no porta bash.
set -eu # sense pipefail: no es POSIX
: "${VELOZ_API_PORT:=8080}" # valor per defecte, POSIX
: "${VELOZ_BD_HOST:?falta VELOZ_BD_HOST}" # obligatoria o avortar (03-06)
espera=0
while ! nc -z "$VELOZ_BD_HOST" 5432; do
espera=$(( espera + 1 ))
[ "$espera" -ge 30 ] && { echo "la base de dades no respon" >&2; exit 1; }
sleep 1
done
echo "veloz-api arrencant al port $VELOZ_API_PORT"
exec /usr/local/bin/veloz-api --port "$VELOZ_API_PORT" "$@"Ni un bashisme: [ ] en lloc de [[ ]], $(( )) que sí que és POSIX, : amb ${var:=} i ${var:?}, echo sense opcions i exec final perquè el servei hereti el PID 1 i rebi els senyals (05-02). La decisió queda documentada a la capçalera, que és tan important com la decisió mateixa.
- Declarar la dependència: comprovar
BASH_VERSINFO
BASH_VERSINFOSi un script requereix Bash 4 o superior, digues-ho i falla aviat amb un missatge clar, en lloc de petar cinquanta línies després amb «syntax error near unexpected token». La comprovació va al principi de lib/comu.sh, just després del shebang, i fa servir BASH_VERSINFO (01-02):
#!/usr/bin/env bash
# lib/comu.sh - llibreria comuna del toolkit. Requereix Bash 4.3+.
if [ -z "${BASH_VERSINFO:-}" ]; then
echo "Error: aquest script requereix Bash, no sh/dash." >&2
exit 1
fi
if (( BASH_VERSINFO[0] < 4 || (BASH_VERSINFO[0] == 4 && BASH_VERSINFO[1] < 3) )); then
echo "Error: cal Bash 4.3 o superior; s'ha trobat ${BASH_VERSION}." >&2
echo "A macOS: brew install bash i feu servir /opt/homebrew/bin/bash." >&2
exit 1
fiDos detalls del codi. La primera comprovació s'escriu amb [ ] i echo expressament: si l'intèrpret resulta ser dash, aquestes dues línies han de funcionar per poder donar el missatge; un [[ ]] aquí produiria l'error críptic que precisament volem evitar. I el missatge diu què cal fer, no només què falta: un error que indica la solució estalvia mitja hora a qui se'l trobi.
- Què aporta cada versió de Bash i el problema de macOS
| Versió | Novetats rellevants | Any |
|---|---|---|
| 3.2 | La de macOS. Sense arrays associatius, sense mapfile, sense ${s^^}, sense &>> |
2006 |
| 4.0 | Arrays associatius (declare -A), mapfile/readarray, ${s^^}/${s,,}, |& |
2009 |
| 4.2 | printf -v amb %(fmt)T (dates sense date), declare -g |
2011 |
| 4.3 | declare -n (referències de nom, 08-03), millores a [[ ]] |
2014 |
| 4.4 | ${var@Q} (posada entre cometes segura), mapfile -d, local - |
2016 |
| 5.0+ | EPOCHSECONDS i EPOCHREALTIME (temps sense date), SRANDOM |
2018-22 |
La frontera pràctica és Bash 4.0: gairebé tot el que fa còmode el Bash modern va arribar allà. Ubuntu 24.04 porta la 5.2, així que a la flota no hi ha problema.
El problema és macOS, que continua amb la 3.2 del 2006 per la llicència GPLv3 de les versions posteriors. Si un company desenvolupa en Mac, els seus scripts fallaran en fer servir declare -A o mapfile encara que als servidors funcionin. Tres respostes possibles: instal·lar Bash modern amb Homebrew i fer servir #!/usr/bin/env bash amb el nou primer al PATH —l'opció normal—; cenyir-se a Bash 3.2, cosa que és renunciar a massa; o desenvolupar dins d'un contenidor amb la mateixa imatge que producció, que a més elimina la resta de diferències d'eines de l'apartat 5.
- Balanç del mòdul 8
El mòdul va començar amb tres preguntes sobre el toolkit: s'entén?, és ràpid?, és segur? Set lliçons després, ~/veloz-ops/ és una altra cosa:
| Lliçó | Què hi va aportar |
|---|---|
| 08-01 | Llegible: estil uniforme, estructura canònica, funcions curtes, comentaris que expliquen el perquè |
| 08-02 | Ràpid: mesurat abans i després; informe-diari.sh de 3 min 12 s a 3,9 s |
| 08-03 | Auditat: sense eval, entrada validada amb llista blanca, secrets fora del codi, temporals segurs, sudo acotat |
| 08-04 | Versionat: història amb motius, branques, etiquetes, .gitignore que protegeix la configuració, hook pre-commit |
| 08-05 | Analitzat: 47 avisos corregits, entre ells un rm -rf amb variable buida; format automàtic amb shfmt |
| 08-06 | Provat: tests/ amb dobles i dades fictícies, executat a cada commit i a CI |
| 08-07 | Amb la portabilitat decidida: Bash 5 documentat i comprovat, POSIX on de debò cal |
I tot sense afegir ni una funció nova. Aquesta és la idea del mòdul: la diferència entre un script que funciona i programari del qual et pots refiar no és en el que fa, sinó en com està fet.
Errors Habituals i Consells
- Posar
#!/bin/shi escriure Bash. L'error central. Si fas servir bashismes, el shebang és#!/usr/bin/env bash. - Provar amb
bash script.shun script que declarash. El shebang s'ignora en invocar-lo així, i el problema queda amagat. Prova ambdash script.sh. - Creure que POSIX és «més segur» o «millor». És més restrictiu: triar-lo sense necessitat produeix codi més llarg, més lent i més difícil de llegir.
- Oblidar les cometes a
[ ]. A[[ ]]perdonava; aquí una variable buida produeix un error de sintaxi. - Suposar que les eines són GNU.
sed -i,date -direadlink -fno existeixen igual a macOS ni a BusyBox, i allà no hi ajuda cap shell. - Consell: un contenidor Alpine a CI costa segons i detecta alhora els bashismes i les diferències de BusyBox.
- Consell: escriu la decisió a la capçalera del fitxer. «Requereix Bash 4.3+» o «POSIX pur: la imatge no porta bash» evita que el següent la desfaci sense voler.
Exercicis
Exercici 1. Converteix aquest fragment a POSIX pur mantenint el comportament.
#!/usr/bin/env bash
ciutats=(Valencia Sevilla Bilbao)
for c in "${ciutats[@]}"; do
[[ $c == V* ]] && echo -e "prioritaria:\t${c^^}"
doneExercici 2. Escriu una funció veloz_fa_dies que retorni la data de fa N dies en format AAAA-MM-DD i funcioni tant amb date de GNU com de BSD.
Exercici 3. Un company informa que informe-diari.sh falla al seu macOS amb declare: -A: invalid option. Explica'n la causa i proposa dues solucions amb les seves contrapartides.
Solucions
Solució 1.
#!/bin/sh
set -- Valencia Sevilla Bilbao # parametres posicionals com a "array"
for c in "$@"; do
case $c in
V*) majus=$(printf '%s' "$c" | tr '[:lower:]' '[:upper:]')
printf 'prioritaria:\t%s\n' "$majus" ;;
esac
doneQuatre substitucions: l'array passa a set -- i "$@"; la comparació amb patró [[ $c == V* ]] passa a case, que és la forma POSIX de comparar amb patrons; ${c^^} passa a tr; i echo -e passa a printf, que interpreta \t de manera portable i a més evita el problema que echo -e imprimeixi literalment -e en alguns shells.
Solució 2.
# veloz_fa_dies <n> -> data AAAA-MM-DD de fa n dies
veloz_fa_dies() {
if date -d '@0' +%F >/dev/null 2>&1; then
date -d "$1 days ago" +%F # GNU
else
date -v "-$1"d +%F # BSD / macOS
fi
}La detecció es fa provant una opció exclusiva de GNU i descartant-ne la sortida i l'error. L'alternativa realment universal és aritmètica sobre l'època —date -d "@$(( $(date +%s) - 86400 * $1 ))"— però té el mateix problema en convertir de tornada, i a més ignora els canvis d'horari, així que la detecció de variant és preferible.
Solució 3. La causa és que macOS porta Bash 3.2, anterior als arrays associatius que van arribar a la 4.0, i #!/usr/bin/env bash resol al /bin/bash del sistema. Dues solucions:
- Instal·lar Bash modern amb
brew install bashi anteposar el seu directori alPATH, de manera queenv bashtrobi el 5.x. Contrapartida: cada persona ha de configurar la seva màquina, i unPATHmal ordenat reprodueix la fallada en silenci. - Desenvolupar en un contenidor amb la mateixa imatge que producció. Contrapartida: flux de treball una mica més pesat; avantatge: elimina també les diferències de
sed,dateistatde l'apartat 5, que apareixerien igualment.
Reescriure el toolkit per a Bash 3.2 seria una tercera opció, i és la pitjor: penalitza tres servidors per acomodar un portàtil. En qualsevol cas, la comprovació de BASH_VERSINFO de l'apartat 8 hauria convertit aquell error críptic en un missatge que explica què cal fer.
Conclusió
La portabilitat és una decisió, no una virtut automàtica. POSIX defineix el mínim comú denominador del shell, i tot el que Bash hi afegeix per sobre —[[ ]], arrays, ${s//a/b}, ${s^^}, mapfile, <<<, <( ), +=, set -o pipefail, trap ERR— és un bashisme que desapareix tan bon punt /bin/sh és dash a Debian, ash a Alpine o ksh en un altre Unix; l'error [[: not found n'és la signatura. La taula d'equivalències cobreix l'essencial: [ "$a" = "$b" ] amb cometes obligatòries, case per comparar amb patrons, set -- i "$@" com a substitut dels arrays, tr i sed en lloc de les expansions de cadena, . en comptes de source, printf en comptes d'echo -e i reestructurar el codi allà on falta pipefail. Però el problema més gran no és al shell sinó a les eines externes: sed -i, date -d, readlink -f, grep -P i stat es comporten de manera diferent a GNU, BSD i BusyBox, i davant d'això només hi caben tres estratègies —cenyir-se a les opcions POSIX, detectar la variant en arrencar o declarar la dependència de coreutils—. La portabilitat es comprova, no se suposa: checkbashisms, shellcheck -s sh, dash -n i, sobretot, una execució real en un contenidor Alpine dins de CI. El criteri de Veloz Envíos queda escrit: lib/comu.sh i els cinc scripts de bin/ continuen sent Bash 5 perquè corren en tres servidors idèntics i renunciar a les seves eines no compraria res, mentre que l'entrypoint.sh del contenidor de la veloz-api s'escriu en POSIX pur perquè la imatge Alpine no porta Bash i la seva lògica és curta. Aquesta dependència es declara i es comprova amb BASH_VERSINFO en arrencar, amb [ ] i echo perquè el missatge arribi fins i tot si l'intèrpret és dash, i dient què cal fer i no només què falta. La frontera pràctica és Bash 4.0 —arrays associatius, mapfile, ${s^^}— amb declare -n a la 4.3, i l'obstacle recurrent és el Bash 3.2 de macOS, que es resol amb Homebrew o desenvolupant en contenidor.
Amb això es tanca el mòdul 8, i amb ell la transformació del toolkit: els mateixos cinc scripts i la mateixa llibreria que van començar el mòdul són ara llegibles, ràpids, auditats, versionats, analitzats, provats i amb la portabilitat decidida, sense haver afegit ni una sola funció nova. Ja saps escriure Bash i ja saps escriure'l bé. El que queda és ajuntar-ho tot. El Mòdul 9 són cinc projectes complets construïts pas a pas, aplicant alhora tot el que s'ha après: un recol·lector d'informació del sistema (09-01), un analitzador de registres que agrega, detecta patrons i genera informes (09-02), un sistema de còpies de seguretat automatitzat amb retenció, verificació i restauració provada (09-03), un monitor de xarxa amb llindars i alertes (09-04) i, com a tancament del curs, la integració final del toolkit (09-05), on les peces dels quatre projectes anteriors s'unifiquen en una eina única, instal·lable, versionada, provada i desplegada a la flota de Veloz Envíos.
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
