En tancar el Mòdul 3 va quedar un mur assenyalat amb el dit: la línia de crontab plena d'escapaments, la canonada de l'informe que ja no cabia a la pantalla, i aquella dependència insuportable que tu te'n recordessis de cada pas a les tres de la matinada. Aquest mòdul enderroca aquell mur amb la idea més simple del món: un script no és res més que un fitxer de text amb les ordres que ja saps escriure.
No hi ha cap llenguatge nou per aprendre: grep, awk, find, curl i df continuen sent els mateixos. El que canvia és que deixen de viure a la teva memòria per viure en un fitxer amb nom, permisos, autor i data; un fitxer que es pot executar igual mil vegades i córrer sol mentre tu dorms. Aquesta lliçó munta els fonaments i acaba amb revisio_salut.sh, el primer script del fil conductor, que les sis lliçons següents aniran millorant.
Contingut
- Val la pena que això sigui un script?
- Què és exactament un script
- El shebang: qui interpreta el teu fitxer
- Les tres formes d'executar un script
- Permisos d'execució
- On viuen els scripts i el PATH
- Anatomia d'un script decent
- Comentaris útils i comentaris inútils
- Codis de sortida
- Primer script real:
revisio_salut.sh - Estil i eines:
shellcheckishfmt
- Val la pena que això sigui un script?
Escriure un script té un cost: cal mantenir-lo, versionar-lo, documentar-lo i recordar que existeix. Abans d'obrir l'editor, situa el que vols fer en aquesta escala.
| Forma | Quan | Avantatge | Límit |
|---|---|---|---|
| One-liner / àlies | Ho fas una vegada, o és una ordre fixa diària | Cost zero, o una línia a .bashrc |
Es perd en tancar la sessió; l'àlies no accepta arguments al mig |
| Funció de shell | Lògica curta amb arguments, només per a tu | Viu al teu entorn, sense subprocés | No la pot executar cron ni cap altre usuari |
| Script | Procediment repetible, amb passos i decisions | Versionable, compartible, programable | Bash es torna incòmode per sobre de ~300 línies |
| Ansible | Configurar màquines, i més d'una | Idempotència i inventari de sèrie | Requereix infraestructura i aprenentatge |
| Llenguatge de programació | Estructures de dades, JSON, concurrència, API | Tipus, tests, biblioteques | Dependències per instal·lar i mantenir |
La regla pràctica: si ho has fet tres vegades a mà, o si ho executarà algú que no ets tu, o si ho executarà cron, és un script. Si a més comença a manejar dades imbricades o a parlar amb API JSON, l'alarma està sonant i toca mirar cap a Python; hi tornarem a 04-07. La revisió de salut que la Marta demana cada matí compleix els tres criteris alhora: és un script.
- Què és exactament un script
Un fitxer de text pla amb ordres que l'intèrpret llegeix i executa en ordre. No es compila, no s'enllaça, no genera binaris.
operador@srv-tramontana:~$ printf 'echo "Hola"\ndate +%%F\n' > /tmp/primer.sh
operador@srv-tramontana:~$ bash /tmp/primer.sh
Hola
2026-08-18bash ha obert el fitxer, ha llegit la primera línia, l'ha executada com si tu l'haguessis teclejada, i ha passat a la segona. Aquesta equivalència total entre «el que teclejes» i «el que va en un script» és la raó que aquest mòdul et resulti natural: ja saps escriure el contingut, només faltava el recipient.
- El shebang: qui interpreta el teu fitxer
Si el fitxer s'executa per si mateix, el nucli necessita saber quin programa l'ha d'interpretar: ho diuen els dos primers caràcters, #!, seguits de la ruta de l'intèrpret. En executar ./script.sh, el nucli llegeix aquells bytes màgics i arrenca en realitat /bin/bash ./script.sh. Sense shebang el resultat depèn d'on siguis, així que no ho deixis mai a l'atzar.
| Shebang | Què fa | Quan fer-lo servir |
|---|---|---|
#!/bin/bash |
Ruta fixa a Bash | Servidors Linux, on Bash sempre hi és |
#!/usr/bin/env bash |
Busca bash al PATH |
Portabilitat: macOS, BSD, Bash a /usr/local |
#!/bin/sh |
El shell POSIX del sistema | Scripts que han de córrer en qualsevol Unix, sense extensions |
En aquest curs farem servir #!/usr/bin/env bash: costa el mateix i t'estalvia el dia que executis l'script en un macOS on el Bash modern és a /opt/homebrew/bin/bash.
Per què /bin/sh no és Bash a Ubuntu
A Ubuntu i Debian, ls -l /bin/sh revela un enllaç a dash, un shell minúscul que implementa POSIX i res més. Es va triar així perquè els scripts d'arrencada són milers i dash els executa molt més ràpid. La conseqüència és que tot el que és específic de Bash falla:
operador@srv-tramontana:~$ cat > /tmp/prova_sh.sh <<'EOF'
#!/bin/sh
if [[ "reserves" == reserv* ]]; then
echo "coincideix"
fi
EOF
operador@srv-tramontana:~$ bash /tmp/prova_sh.sh
coincideix
operador@srv-tramontana:~$ sh /tmp/prova_sh.sh
/tmp/prova_sh.sh: 2: [[: not foundEl mateix fitxer, dos intèrprets, dos resultats. [[ ]] és de Bash, igual que les matrius, ${VAR^^}, local -n o <<<. I fixa't en el detall cruel: l'script no va fallar en escriure'l, va fallar en executar-se amb l'intèrpret equivocat, possiblement setmanes després i dins de cron. Si escrius #!/bin/sh, no facis servir res de Bash.
- Les tres formes d'executar un script
N'hi ha tres —bash script.sh arrenca un Bash nou que llegeix el fitxer, ./script.sh deixa que el nucli llegeixi el shebang, i source script.sh (o . script.sh, la forma POSIX) l'executa el shell actual— i la diferència no és cosmètica: canvia en quin procés s'executen les teves ordres.
flowchart LR
A["El teu shell interactiu<br/>PID 3120, cwd=/home/operador"] -->|"bash script.sh<br/>./script.sh"| B["Subprocés Bash<br/>PID 3455, còpia de l'entorn"]
B -->|"en acabar, mor"| C["El shell original<br/>no ha canviat"]
A -->|"source script.sh"| D["Mateix procés PID 3120<br/>cd, variables i funcions persisteixen"]
La demostració clàssica, un script que canvia de directori:
operador@srv-tramontana:~$ cat > /tmp/anar_releases.sh <<'EOF'
#!/usr/bin/env bash
cd /opt/tramontana/releases
echo "Dins de l'script soc a: $PWD"
EOF
operador@srv-tramontana:~$ chmod +x /tmp/anar_releases.sh
operador@srv-tramontana:~$ /tmp/anar_releases.sh
Dins de l'script soc a: /opt/tramontana/releases
operador@srv-tramontana:~$ pwd
/home/operador
operador@srv-tramontana:~$ source /tmp/anar_releases.sh
Dins de l'script soc a: /opt/tramontana/releases
operador@srv-tramontana:~$ pwd
/opt/tramontana/releasesL'script sí que va canviar de directori... en el seu propi procés, que ja no existeix. Un fill hereta una còpia de l'entorn del seu pare, però res del que el fill canviï no torna al pare: ni el directori, ni les variables, ni les funcions. És l'herència d'una sola direcció de 03-01; amb source no hi ha procés nou i per això el cd persisteix.
| Forma | Procés nou? | Cal chmod +x? |
Respecta el shebang? | Efectes que persisteixen |
|---|---|---|---|---|
bash script.sh |
Sí | No | No (mana bash) |
Cap |
./script.sh |
Sí | Sí | Sí | Cap |
source script.sh |
No | No | No | cd, variables, funcions |
Dues regles pràctiques. Els scripts s'executen amb ./ o pel seu nom, l'única forma que respecta el shebang i la que farà servir cron. I source es reserva per a configuració i biblioteques de funcions, que és per al que el farem servir a 04-05. Un avís: com que source no crea cap procés, un exit 1 dins d'un fitxer que fas source al teu terminal et tanca la sessió. Li ha passat a tothom una vegada.
- Permisos d'execució
Un fitxer de text no és executable fins que li ho dius al sistema. Reprenent 02-07:
operador@srv-tramontana:~/scripts$ ./revisio_salut.sh
-bash: ./revisio_salut.sh: Permission denied
operador@srv-tramontana:~/scripts$ chmod +x revisio_salut.sh && ls -l revisio*
-rwxr-x--- 1 operador operador 512 Aug 18 09:14 revisio_salut.shchmod +x respecta l'umask 027 del Mòdul 2: afegeix x a usuari i grup, no a altres; chmod 750 diu el mateix sense dependre de l'umask. Dos matisos: el bit x no significa «això és codi màquina» sinó «permet-me intentar executar-ho» —qui decideix com interpretar-ho és el shebang—, i bash script.sh funciona sense bit x perquè allà el fitxer només es llegeix, que és la manera còmoda de provar una cosa a mig escriure.
- On viuen els scripts i el PATH
Teclejar /home/operador/scripts/revisio_salut.sh cada matí garanteix que ningú no el faci servir. La solució és el PATH, que ja vas disseccionar a 03-01.
| Ubicació | Per a qui | Notes |
|---|---|---|
~/scripts |
Tu, amb ruta explícita | On viu el codi font en aquest curs |
~/bin o ~/.local/bin |
Només el teu usuari | Ubuntu l'afegeix al PATH si existeix en iniciar la sessió |
/usr/local/bin |
Tots els usuaris | El lloc correcte per a scripts locals del sistema (/usr/bin és del gestor de paquets: no hi posis mai res teu) |
operador@srv-tramontana:~$ mkdir -p ~/bin ~/scripts
operador@srv-tramontana:~$ ln -s ~/scripts/revisio_salut.sh ~/bin/revisio-salut
operador@srv-tramontana:~$ source ~/.profile && which revisio-salut
/home/operador/bin/revisio-salutFem servir un enllaç simbòlic en comptes de moure el fitxer: el codi continua a ~/scripts (versionat a git, ja a 04-07) i ~/bin només publica un nom còmode, sense extensió i amb guionets, com les ordres d'Unix. Continua vigent la regla del Mòdul 3: . mai al PATH, perquè n'hi hauria prou que algú deixés un fitxer anomenat ls en un directori compartit perquè executessis el seu codi sense saber-ho.
- Anatomia d'un script decent
Aquesta és la plantilla amb què començaràs tots els teus scripts a partir d'avui. Cada línia evita un problema concret que veuràs durant el mòdul.
#!/usr/bin/env bash
#
# nom.sh - Una línia dient què fa.
#
# Autor : Nom Cognom <correu>
# Data : 2026-08-18
# Ús : nom.sh [opcions] <argument>
#
# Descripció una mica més llarga si cal: què comprova, què modifica,
# què deixa escrit i on.
set -euo pipefail
# --- Constants -----------------------------------------------------------
DIRECTORI_LOG="/var/log/tramontana"
LLINDAR_DISC=80
# --- Cos -----------------------------------------------------------------
# ... aquí la feina real ...
exit 0- Capçalera. Nom, propòsit, autor, data i manera d'ús: quan d'aquí a vuit mesos trobis aquest fitxer a les quatre de la matinada, aquelles cinc línies valdran més que tota la resta.
set -euo pipefail. El mode estricte:-eavorta si una ordre falla,-uavorta si fas servir una variable no definida, ipipefailfa que una canonada falli si falla qualsevol dels seus trams, no només l'últim (ho vam anunciar a 03-04). Posa-ho des d'avui a tot el que escriguis; el perquè detallat i —sobretot— on no funciona és el cor de 04-06.- Constants en MAJÚSCULES, minúscules per a les variables de treball, i totes agrupades a dalt: canviar un llindar no ha d'obligar a llegir l'script sencer.
exit 0explícit. Sense ell, l'script retorna el codi de l'última ordre, que pot ser qualsevol cosa.exit 0diu «he arribat fins aquí i tot ha anat bé», i això és el que llegeixen cron i la monitoració.
- Comentaris útils i comentaris inútils
Tot el que segueix un # s'ignora fins al final de línia, tret del shebang. Però comentar molt no és comentar bé.
# INÚTIL: repeteix el que el codi ja diu
us=$(df --output=pcent / | tail -1) # assigna l'ús de disc a us
# ÚTIL: documenta una decisió que sembla un error
# No fem servir 'grep -c' a seques perquè retorna 1 si no hi ha coincidències
# i amb 'set -e' això avortaria l'script un dia tranquil sense errors.
errors=$(grep -c "^$avui" "$LOG_ERRORS" || true)La regla: el codi diu què fa; el comentari diu per què. Si necessites un comentari per entendre què fa una línia, la solució sol ser reescriure-la o extreure-la a una funció amb bon nom (04-05).
- Codis de sortida
Tot procés acaba retornant un enter de 0 a 255. Ja el coneixes com a $?; ara ets tu qui el produeix, i això canvia la responsabilitat: el codi de sortida és l'única part del teu script que un altre programa llegirà. La convenció és a l'inrevés del que és intuïtiu —0 és èxit— i té sentit: hi ha una sola manera d'encertar i moltes de fallar, cadascuna amb el seu número.
| Codi | Significat |
|---|---|
0 |
Èxit |
1 |
Error genèric |
2 |
Ús incorrecte: falten arguments, opció desconeguda |
126 / 127 |
Existeix però no s'ha pogut executar (falta el bit x) / ordre no trobada (típicament, el PATH de cron) |
128+N |
Acabat pel senyal N: 130 = Ctrl+C, 143 = SIGTERM, 137 = SIGKILL |
(I exit -1 acaba en 255, fora de rang.) exit sense argument retorna el codi de l'última ordre: sigues explícit. I evita inventar-te codis per sobre de 125, que xoquen amb els reservats; en tens de sobres amb el rang 3-125 per als teus propis significats, documentats a la capçalera. A 04-03 formalitzarem una taula per als nostres scripts.
- Primer script real:
revisio_salut.sh
revisio_salut.shLa Marta demana el mateix cada matí: «està amunt la web, queda disc, i hi ha hagut errors aquesta nit?». L'escrivim tal qual, com una tirada d'ordres, aplicant la plantilla de l'apartat anterior.
#!/usr/bin/env bash
#
# revisio_salut.sh - Revisió ràpida de salut de Tramontana Reserves.
#
# Autor : Operador de sistemes <operador@srv-tramontana>
# Data : 2026-08-18
# Ús : revisio_salut.sh
#
# Comprova tres coses: que l'aplicació respon al port 8080, quant disc
# queda a l'arrel i quants errors s'han registrat avui. No modifica res:
# és de només lectura i segur d'executar en producció.
set -euo pipefail
# --- Constants -----------------------------------------------------------
URL_SALUT="http://10.0.2.15:8080/salut"
LOG_ERRORS="/var/log/tramontana/errors.log"
LLINDAR_DISC=80
ESPERA_MAX=5
# --- Cos -----------------------------------------------------------------
echo "=== Revisió de salut de Tramontana Reserves ==="
echo "Servidor : $(hostname)"
echo "Data : $(date '+%F %T')"
echo
# -s silencia la barra de progrés, -o /dev/null llença el cos de la
# resposta, -w imprimeix només el codi, --max-time evita penjar-se.
codi_http=$(curl -s -o /dev/null -w '%{http_code}' \
--max-time "$ESPERA_MAX" "$URL_SALUT" || true)
echo "HTTP 8080 : $codi_http"
# --output=pcent dona només la columna del percentatge; tail -1 salta la
# capçalera "Use%"; tr -dc '0-9' deixa el número net per comparar.
us_disc=$(df --output=pcent / | tail -1 | tr -dc '0-9')
echo "Disc / : ${us_disc}% usat (llindar ${LLINDAR_DISC}%)"
# grep -c retorna 1 quan no troba res i amb set -e això avortaria
# l'script justament el dia que tot va bé. D'aquí el || true.
avui=$(date '+%Y-%m-%d')
errors_avui=$(grep -c "^$avui" "$LOG_ERRORS" || true)
echo "Errors avui: $errors_avui"
exit 0operador@srv-tramontana:~$ chmod 750 ~/scripts/revisio_salut.sh
operador@srv-tramontana:~$ ~/scripts/revisio_salut.sh; echo "codi: $?"
=== Revisió de salut de Tramontana Reserves ===
Servidor : srv-tramontana
Data : 2026-08-18 09:22:41
HTTP 8080 : 200
Disc / : 30% usat (llindar 80%)
Errors avui: 6
codi: 0Ja és infinitament millor que tres ordres a l'historial. Però és honestament dolent, i convé que vegis per què des del principi, perquè aquella llista és l'índex de la resta del mòdul:
- Les constants són dins de l'script i no accepta opcions: ni
-h, ni un llindar diferent, ni mode silenciós (04-02 i 04-03). - Imprimeix el llindar però no el compara amb res. No hi ha cap decisió: si el disc estigués al 95 % diria «95%» tan tranquil (04-04).
- Tres blocs gairebé idèntics que demanen a crits ser funcions (04-05), i si
errors.logno existeix l'script mor a mitges amb un missatge lleig (04-06). - Sempre retorna 0, així que cap monitoració no el pot fer servir (04-07).
Desa'l tal qual: al final del mòdul el compararàs amb la seva versió final.
- Estil i eines:
shellcheck i shfmt
shellcheck i shfmtBash té una sintaxi plena de paranys i un intèrpret que gairebé mai no es queixa: escriu $fitxer sense cometes i funcionarà durant mesos, fins al dia que aparegui un nom amb un espai. L'anàlisi estàtica no és opcional en shell.
operador@srv-tramontana:~$ sudo apt install -y shellcheck shfmt
operador@srv-tramontana:~$ printf '#!/usr/bin/env bash\ndir=/opt/tramontana/releases\ncd $dir\nrm -f $1\n' > /tmp/dolent.sh
operador@srv-tramontana:~$ shellcheck /tmp/dolent.sh
In /tmp/dolent.sh line 3:
cd $dir
^--^ SC2086: Double quote to prevent globbing and word splitting.
^-----^ SC2164: Use 'cd ... || exit' in case cd fails.
In /tmp/dolent.sh line 4:
rm -f $1
^-- SC2086: Double quote to prevent globbing and word splitting.Tres avisos en quatre línies i tots tres són bombes de rellotgeria: sense cometes, un directori amb espais es parteix en dos arguments; i si el cd falla, el rm -f s'executa al directori on estiguessis. Cada codi SCxxxx té la seva pàgina al wiki de ShellCheck; a 04-06 esmicolarem els quatre més freqüents. La regla del mòdul des d'avui: cap script no es dona per acabat fins que shellcheck no diu res.
operador@srv-tramontana:~$ shellcheck ~/scripts/revisio_salut.sh && echo "Net"
Net
operador@srv-tramontana:~$ shfmt -i 4 -d ~/scripts/revisio_salut.sh # -d: només el diff
operador@srv-tramontana:~$ shfmt -i 4 -w ~/scripts/revisio_salut.sh # -w: reescriushfmt formata en lloc de criticar: -i 4 fixa quatre espais, -d ensenya què canviaria sense tocar res (el costum de --dry-run del curs) i -w escriu. Sobre estil, tres decisions que no discutirem més: quatre espais d'indentació (mai tabuladors, que es trenquen en copiar), línies de menys de 100 caràcters partint amb \, i una instrucció per línia.
Errors Comuns i Consells
- Escriure l'script a Windows i pujar-lo. Els finals CRLF fan que el shebang sigui
#!/usr/bin/env bash\ri l'error,bad interpreter: No such file or directory, no diu res. Diagnostica'l ambfile script.shi arregla'l ambdos2unix. - Deixar línies abans del shebang. Ha de ser la primera línia, començant a la columna 1. I no anomenis
test.shel teu script:testés un builtin i el conflicte de noms dona maldecaps. - Executar amb
sh script.shun script amb shebang de Bash. El shebang s'ignora quan invoques l'intèrpret a mà: és la causa número u de «funciona al meu terminal i falla al servidor». - Esperar que un script canviï el teu directori o les teves variables. No pot: és un altre procés. Si de debò ho necessites, és una funció o un fitxer per fer
source. I no oblidis l'exit 0final: si l'última línia és ungrepsense coincidències, el teu script correcte retorna 1 i cron t'avisa d'una fallada inexistent. - Consell: durant el desenvolupament,
bash -n script.shcomprova la sintaxi sense executar res; costa un segon i evita descobrir unfique falta a mig desplegament. Integra a mésshellcheckal teu editor i comença cada script copiant la plantilla de l'apartat 7.
Exercicis
Exercici 1. Demostra empíricament, amb un sol fitxer i sense editar-lo entre proves, la diferència entre bash script.sh, ./script.sh i source script.sh. L'script ha de definir una variable, canviar de directori i imprimir el seu propi PID. Explica què observes en cada cas i per què.
Exercici 2. Escriu ~/scripts/info_release.sh: quina versió de Tramontana està activa (resolent /opt/tramontana/app), quant ocupa aquell release i quan es va desplegar. Aplica la plantilla completa, deixa'l net de shellcheck i publica'l a ~/bin com a info-release.
Exercici 3. En Luis ha deixat aquest script al servidor. Troba-hi quatre problemes diferents sense executar-lo, justifica'n cadascun i reescriu-lo.
#! /bin/sh
# neteja temporals
cd /srv/tramontana/backups/temporals
rm -rf *
if [[ $? == 0 ]]; then echo ok; fiSolucions
Solució 1. $$ conté el PID del shell que executa el codi: és el testimoni que delata si hi ha hagut procés nou.
operador@srv-tramontana:~$ cat > /tmp/demo_ambit.sh <<'EOF'
#!/usr/bin/env bash
echo "PID de l'script : $$"
LA_MEVA_VARIABLE="definida dins"
cd /opt/tramontana/releases
echo "Directori dins : $PWD"
EOF
operador@srv-tramontana:~$ chmod +x /tmp/demo_ambit.sh; echo "El meu shell: $$"
El meu shell: 3120
operador@srv-tramontana:~$ /tmp/demo_ambit.sh
PID de l'script : 3456
Directori dins : /opt/tramontana/releases
operador@srv-tramontana:~$ echo "$PWD - ${LA_MEVA_VARIABLE:-(no existeix)}"
/home/operador - (no existeix)
operador@srv-tramontana:~$ source /tmp/demo_ambit.sh
PID de l'script : 3120
Directori dins : /opt/tramontana/releases
operador@srv-tramontana:~$ echo "$PWD - ${LA_MEVA_VARIABLE:-(no existeix)}"
/opt/tramontana/releases - definida dinsbash /tmp/demo_ambit.sh dona el mateix resultat que ./: PID diferent del del teu shell, per tant procés nou, i el cd i la variable moren amb ell. Només canvia el mecanisme: bash fitxer arrenca Bash explícitament i ignora el shebang, mentre que ./fitxer fa que el nucli llegeixi el shebang i decideixi —i per això aquell cas, i només aquell, exigeix el bit x—. El tercer imprimeix el mateix PID 3120: no hi ha procés nou, l'ha executat el teu propi Bash, i per això tot persisteix. El ${LA_MEVA_VARIABLE:-(no existeix)} evita que echo imprimeixi un buit ambigu; el veuràs en detall a 04-02.
Solució 2.
#!/usr/bin/env bash
#
# info_release.sh - Informa del release actiu de Tramontana Reserves.
#
# Autor : Operador de sistemes <operador@srv-tramontana>
# Data : 2026-08-18
# Ús : info_release.sh (només lectura)
set -euo pipefail
ENLLAC_APP="/opt/tramontana/app"
# readlink -f resol l'enllaç fins al seu destí final en ruta absoluta,
# necessari perquè 'app' és un enllaç *relatiu* al release actiu.
ruta_release=$(readlink -f "$ENLLAC_APP")
versio=$(basename "$ruta_release")
mida=$(du -sh "$ruta_release" | cut -f1)
# stat sobre l'ENLLAÇ (no sobre el seu destí) dona quan es va canviar, que
# és exactament quan es va desplegar. cut treu la fracció de segon.
desplegat=$(stat -c '%y' "$ENLLAC_APP" | cut -d'.' -f1)
printf 'Release actiu : %s\nRuta : %s\n' "$versio" "$ruta_release"
printf 'Mida : %s\nDesplegat : %s\n' "$mida" "$desplegat"
exit 0operador@srv-tramontana:~$ chmod 750 ~/scripts/info_release.sh
operador@srv-tramontana:~$ shellcheck ~/scripts/info_release.sh && echo "Net"
Net
operador@srv-tramontana:~$ ln -s ~/scripts/info_release.sh ~/bin/info-release
operador@srv-tramontana:~$ info-release
Release actiu : 3.2.1
Ruta : /opt/tramontana/releases/3.2.1
Mida : 98M
Desplegat : 2026-08-11 17:42:03Solució 3. Els quatre problemes, de més greu a menys:
cdsense comprovar seguit derm -rf *. El defecte letal: si el directori no existeix o no hi tens permís, elcdfalla, l'script continua on estiguessis i esborra tot el que hi hagi allà. És SC2164, i s'arregla ambcd ... || exito amb mode estricte.#! /bin/shamb[[ ]]. Dos errors: l'espai després de#!l'admet Linux però no tots els Unix, i sobretot/bin/shés dash, que no coneix[[ ]]. L'script mor a l'última línia amb[[: not found.if [[ $? == 0 ]]. Redundant i fràgil: en Bash es ramifica directament sobre l'ordre (if rm -rf ...; then), com veurem a 04-04. A més==compara cadenes on s'hauria de fer servir un test numèric.- Falta tota la resta: sense capçalera, sense mode estricte, sense
exitexplícit, i el comentari «neteja temporals» no diu què considera temporal ni des de quan. Unrm -rf *mereix més explicació que cap altra línia del fitxer.
La versió reescrita fa a més el que el nom promet —esborrar l'antic, no tot—:
#!/usr/bin/env bash
#
# netejar_temporals.sh - Esborra els temporals de còpia amb més de 7 dies.
# Autor : Operador de sistemes <operador@srv-tramontana> Data: 2026-08-18
set -euo pipefail
DIR_TEMPORALS="/srv/tramontana/backups/temporals"
DIES_RETENCIO=7
# -mindepth 1 no toca el propi directori; -xdev no creua muntatges;
# -delete evita dependre d'un glob que podria quedar sense expandir i
# intentar esborrar un fitxer anomenat literalment *.
find "$DIR_TEMPORALS" -mindepth 1 -xdev -type f \
-mtime +"$DIES_RETENCIO" -delete
echo "Temporals de més de ${DIES_RETENCIO} dies eliminats."
exit 0Ja no hi ha cd, així que el perill desapareix d'arrel, i el mode estricte avorta si find falla.
Conclusió
Tens els fonaments, i són més dels que sembla.
- Saps quan escriure un script i quan n'hi ha prou amb un àlies, una funció o Ansible, amb la regla de les tres repeticions com a criteri.
- Entens que un script és text pla amb ordres, domines el shebang i per què
#!/usr/bin/env bashés l'elecció per defecte, i coneixes el parany que a Ubuntu/bin/shés dash i[[ ]]no hi existeix. - Distingeixes les tres formes d'executar un script i per què només
sourceafecta el teu shell; col·loques els scripts a~/scripts, els publiques amb un enllaç a~/bini continues sense posar.al PATH. - Arrenques tot script amb la mateixa plantilla —shebang, capçalera amb ús,
set -euo pipefail, constants en majúscules, cos iexit 0—, comentes el perquè, retornes codis de sortida amb significat i passesshellcheckabans de donar res per acabat.
revisio_salut.sh ja existeix i ja funciona, però té les constants clavades al codi, no compara res i no sap dir si el resultat és bo o dolent. A la lliçó següent, Variables i Tipus de Dades, ataquem la primera mancança: veuràs que en Bash tot és una cadena i què implica això, dominaràs l'expansió de paràmetres —aquella col·lecció de ${VAR#...}, ${VAR:-...} i ${VAR//.../...} que converteix deu línies en una—, aprendràs per què Bash no sap sumar decimals i què fer amb l'import mitjà de reserves.csv, i comptaràs reserves per casa amb matrius associatives sense sortir del shell. En acabar-la, revisio_salut.sh tindrà la seva configuració fora del cos de l'script.
Curs de Linux: De Principiant a Administrador de Sistemes
Mòdul 1: Introducció a Linux
- Què és Linux?
- Història de Linux
- Distribucions de Linux
- Instal·lant Linux
- Primer Contacte amb el Sistema
- Estructura del Sistema de Fitxers de Linux
Mòdul 2: Comandes Bàsiques de Linux
- Introducció a la Línia de Comandes
- Obtenir Ajuda i Documentació del Sistema
- Navegant pel Sistema de Fitxers
- Operacions amb Fitxers i Directoris
- Visualització i Edició de Fitxers
- Enllaços Durs i Simbòlics
- Permisos i Propietat dels Fitxers
Mòdul 3: Habilitats Avançades en la Línia de Comandes
- L'Entorn del Shell: Variables, Àlies i Historial
- Ús de Comodins i Expressions Regulars
- Cerca de Fitxers i Contingut: find, locate i grep
- Canonades i Redirecció
- Processament de Text: cut, sort, uniq, sed i awk
- Gestió de Processos
- Programació de Tasques amb Cron
- Comandes de Xarxa
Mòdul 4: Scripting en Shell
- Introducció al Scripting en Shell
- Variables i Tipus de Dades
- Entrada, Sortida i Arguments d'un Script
- Estructures de Control
- Funcions i Biblioteques
- Depuració i Gestió d'Errors
- Scripts de Producció: Bones Pràctiques
Mòdul 5: Administració del Sistema
- Gestió d'Usuaris i Grups
- sudo i Permisos Especials
- Gestió de Paquets
- Gestió de Discs
- systemd i la Gestió de Serveis
- Registres del Sistema: journald i syslog
- Monitoratge del Sistema i Optimització del Rendiment
- Còpies de Seguretat i Restauració
Mòdul 6: Xarxes i Seguretat
- Configuració de Xarxes
- SSH i Accés Remot
- Tallafocs i Seguretat Perimetral
- Sistemes de Detecció d'Intrusions
- Gestió de Secrets i Certificats TLS
- Assegurant Sistemes Linux
Mòdul 7: Temes Avançats
- El Procés d'Arrencada i la Recuperació del Sistema
- Diagnòstic Avançat: strace, perf i eBPF
- Optimització del Nucli de Linux
- Virtualització amb Linux
- Contenidors de Linux i Docker
- Automatització amb Ansible
- Alta Disponibilitat i Balanceig de Càrrega
