La shell Bash ens permet crear programes útils per realitzar tasques repetitives a nivell de sistema operatiu; automatitzar còpies de seguretat, esquemes de directoris, cerques de patrons complexes, gestionar usuaris i els seus permisos ...
Què són els scripts dels SO?
Els intèrprets d’ordres o shells són programes que permeten la interacció dels usuaris amb el S.O. i el seu hardware. També incorporen llenguatges de programació per a crear programari que anomenem scripts (en català, guions).
Els scripts de shell són molt útils per fer tasques de gestió i administració del sistema (com monitoritzar les tasques en execució) i altres treballs repetitius que no requereixen un llenguatge de programació més sofisticat (per exemple, còpies de seguretat)
Intèrprets d’ordres a Windows
Command Prompt (cmd.exe): Aquest és l’intèrpret d’ordres clàssic de Windows. Equivalent i compatible al COMMAND.COM d’MS-DOS i versions de Windows de 16 i 32 bits. Té dos modes d’execució:
- Interactiu: l’usuari escriu les ordres per ser executades
- Mode per lots (batch): executa una sentència predefinida d’ordres guardada en un .bat
Windows PowerShell: interfície de consola per a S.O. Windows llançada el 2006, incorporat des de Windows 7, que té com a utilitat principal l’automatització de tasques administratives més avançades. Té una sintaxi més moderna, basada en la programació orientada a objectes.
Els 2 intèrprets coexisteixen i s’utilitzen per propòsits diferents.
Intèrprets d’ordres a Linux
El shell Bash (Bourne-Again Shell) és l’intèrpret d’ordres predeterminat de gairebé totes les distribucions GNU/Linux, així com de Mac OS X, i pot executar-se en la majoria dels sistemes operatius tipus Unix.
Se’n poden instal·lar d’altres a Linux, com Zsh que incorpora algunes funcionalitats més avançades i més personalització.
Intèrprets d’ordres a Mac
Tant macOS (originalment OS X) com Linux tenen les seves arrels en Unix, un sistema operatiu desenvolupat als anys 70 amb llicència BSD () i àmpliament utilitzat per implantar sistemes operatius multiusuari els anys 80. Aquesta herència comuna ha fet que molts components i idees siguin compartides entre ambdós sistemes operatius, incloent-hi els shells.
Quan Apple va llançar OS X (ara macOS) el 2001, es va basar en un nucli Unix BSD i va triar Bash (Bourne Again Shell) com a shell predeterminat per la seva popularitat i compatibilitat amb scripts existents.
Un dels dubtes més freqüents quan s’estudien les llicències dels SO és com pot ser que Mac i Linux, que tenen un enfocament totalment oposat respecte les llibertats del usuaris, poden compartir els mateixos intèrprets d’ordres, part del programari i la arquitectura.
Apple va poder utilitzar components del sistema operatiu BSD (Berkeley Software Distribution), una variant d’Unix desenvolupada a la Universitat de Califòrnia, Berkeley. BSD té una llicència més permissiva que la GPL (General Public License) de Linux, que permet l’ús i la distribució de codi modificat amb menys restriccions. És a dir, que permet llicenciar el programari derivat amb una llicència propietària d’Apple.
Com executar un script a Linux ?
Abans de començar a entendre la sintaxi del llenguatge d’scripts de Bash. El que farem és crear un nou script, a partir d’un fitxer amb instruccions, li donarem els permisos per a que sigui executable i finalment l’executarem.
Per a crear el teu script amb la shell de Linux obre el terminal (cerca el programa que té una pantalla negre com a icona , o usa la drecera Ctrl+Alt+T)
- Crea el fitxer
hacking.shamb un editor com nano o gedit, amb extensió sh.
#!/bin/bash
for
do
done
- Converteix-lo a programa, assignant permisos d’execució.
- Executa i a gaudir :)
Resultat esperat: Cada 2 segons sortirà el mateix missatge, a excepció del número % completed, que gràcies al bucle s’anirà incrementant.
Una alternativa als passos 2 i 3, si no ets un usuari amb permisos d’administrador (no estàs al grup sudo), és aquesta:
Variables locals i variables d’entorn
Al shell, una variable és un nom que representa un valor que volem guardar pel seu posterior ús en un o més punts dels nostres programes.
Poden ser:
- Locals: només són visibles pel shell en el qual estem treballant, no són visibles per cap shell fill.
Per a declarar variables és important recordar que:
- Les variables d’entorn no poden tindre espais, i si volem assignar un valor amb espai hem de “entrecomillar”, o bé precedir l’espai per un
caràcter d’escapament. - Per mostrar la variable mitjançant la funció
echol’hem de precedir amb el símbol de dòlar$.
NOM='Katy Perry'
Katy Perry
NOM=Katy\ Perry
Katy Perry
Per a eliminar una variable d’entorn podem usar la comanda unset.
Per exemple:
D’aquesta manera podrem fer inteccacions com les següents:
variable1='Sabates negres'
variable2=20.5
L’article Sabates negres costa 20.5 euros
- D’entorn: són visibles tant pel shell pare com pels shells fills. Per defecte disposem de variables d’entorn predefinides que ens poden resultar útils per a la programació d’scripts.
Hi ha diverses ordres relacionades amb les variables:
Ordre set Permet veure totes les variables (locals i d’entorn) definides en una sessió.
Ordre env Permet veure les variables d’entorn definides en una sessió.
Exemples típics:
- USER: Nom de l’usuari actiu
- HOME: Directori de l’usuari (per defecte /home/USER )
- PWD: Directori on es troba l’usuari
- PATH: Llista de directoris on cercar programes abans de buscar-los al disc. Permet executar un programa sense dir-li la ruta sencera.
Si volem veure el valor d’una variable en concret; la instrucció és igual que si fos una de local.
Possible resultat:
Si volem guardar totes les variables d’entorn en un fitxer usem l’operador de redirecció >:

Caràcters especials.
Hi ha caràcters que per a la shell tenen un significat especial. Existeixen diferents tècniques per tal que la shell ignori aquest significat o el tingui en compte:
**** anul·la el significat especial del caràcter que va darrera
‘’ anul·la el significat especial de tots els caràcters que estiguin dins les cometes
“” anul·la el significat especial de tots els caràcters excepte: $ \ `` “”
Exemple: echo “Això és \”una prova\””
Exemple: echo “Sóc el/la $LOGNAME i estic a $PWD: $PWD”
Tractament de la data del sistema.
Saber la data i hora del sistema en funció de la nostra zona horària és molt important per a certes tasques: monitoritzar la activitat d’un ordinador servidor, posar nom i data de les còpies de seguretat…
Per mostrar la data del sistema en format llarg ho podem fer cridant la funció del sistema date; fixa’t que per a què es mostri el resultat de la funció l’hem de rodejar entre parèntesis i un símbol de dòlar: $(date)
Si volem un format més curt i propi de la nostra zona (que es mostri en format dd/mm/aaaa i la hora per separat) ho podem fer assignant el format que volem com a paràmetre.
data=
hora=
Data en format ddmmaaaa: 06/08/2024 Hora en format hh:mm:ss: 22:40:33
En ocasions el sistema no detectarà automàticament el nostre fus horari (això passa en màquines virtuals sobretot) i si és el cas el podrem consultar i editar:
Recurs ampliació.
[https://learning.lpi.org/es/learning-materials/102-500/108/108.1/](Certificació Linux LPI 102, zones horàries)
Exercici 1. Crea un script que crei una carpeta dins del directori actual (on et trobes) amb el nom projecte-<data_avui>-<hora_avui> i al final informi de la seva creació correcta. Recorda que pots usar instruccions com mkdir i cd.
Observació Per ara no farem el tractament de què fer si existeix una carpeta igual (ja el farem un cop vists els condicionals)
{% sol %}
ex1-scr.sh
data=
hora=
carpeta="projecte--"
Possible resultat execució:
{% endsol %}
Pas de paràmetres.
Un script és un fitxer que conté comandos Bash executables. Els fitxers ocults de configuració de Bash com .bash_profile o .bashrc, vistos en la part de la gestió d’usuari són exemples de scripts.
Principalment Bash utilitza variables de tipus cadena de caràcters. Això li diferencia d’altres llenguatges de programació on les variables poden tenir diferents tipus predefinits. Encara que aquest és el tipus per defecte de les variables de Bash, més endavant veurem que les variables en Bash també poden tindre altres tipus, com per exemple números amb els quals realitzar operacions aritmètiques; tal i com passa amb els llenguatges de tipat dinàmic com Python o Javascript.
Per conveni les variables d’entorn exportades (les que passem als subprocesos) s’escriuen en majúscules, i les que no exportem en minúscules.
Aquesta regla, més que per la manera interactiva, és especialment seguida pels scripts i funcions que començarem a programar ara.
Els paràmetres posicionals són els encarregats de rebre els arguments d’un script i els paràmetres d’una funció.
Els seus noms són 1, 2, 3, etc., amb el que per a accedir a ells utilitzarem, com normalment, el símbol $ de la forma $1, $2, $3, etc.
A més tenim el paràmetre posicional 0 ($0) que emmagatzema el nom del script on s’executa.
#!/bin/bash
#Exemple de script que rep paràmetres y les imprimeix
Si ho hem guardat en un fitxer anomenat rep amb el permís d’execució activat podem executar-lo així:
Resultat:
Codis de terminació.
En UNIX les comandes acaben retornant un codi numèric al qual es diu codi de terminació (exit estatus) que indica si el comando va tindre èxit o no.
Encara que no és obligatori que siga així, normalment un codi de terminació 0 significa que el comando va acabar correctament, i un codi entre 1 i 255 correspon a possibles codis d’error.
Per a llegir el codi de terminació de l’últim comando executat disposem de la variable ?, el valor del qual és $?.
Per exemple:
1
La variable ? ha de ser llegida junt després d’executar la comandes, doncs és molt típic guardar el seu valor en una variable ct=$? per al seu posterior ús.
Condicions: if, elif, else
La sentència condicional if permet executar diferents ordres en funció d’una condició.
En Bash, la seva estructura bàsica és:
if
then
# Sentències si la condició és certa
elif
then
# Sentències si la segona condició és certa
else
# Sentències si cap condició anterior és certa
Exemple: Pregunta a l’usuari un número i comprova si un número és positiu, negatiu o 0.
#!/bin/bash
if
then
elif
then
else
Lectura de fitxers.
Ara veurem com llegir un fitxer que tinguem al disc dur. Comprovarem que sigui un fitxer vàlid.
Creem un fitxer de prova amb el nano o l’editor que volgueu:
prova.csv
nom,edat,ciutat
Joan,25,Barcelona
Anna,30,Girona
Marc,22,Tarragona
Fanny,21,BarcelonaPer llegir-lo, en cas que existeixi, ho fem així:
#!/bin/bash
if
then
else
El paràmetre -f verifica que prova.csv sigui un fitxer vàlid.
La comanda cat mostra tot el contingut del fitxer.
Si necessites una solució més robusta, per a qualsevol fitxer passat per paràmetre:
#!/bin/bash
# Comprovar si s'ha passat un fitxer
if ; then
fi
fitxer=""
# Comprovar si el fitxer existeix
if ; then
fi
# Mostrar el contingut del CSV (sense la capçalera)
Exemple lectura/escriptura de fitxers i directoris.
En moltes ocasions necessitem crear una estructura de directoris per a projectes.
Per exemple; crear un script al qual li passis el nom d’un projecte.
Si no existeix una carpeta amb el nom de projecte crearà: a. La carpeta amb el nom del projecte b. Les subcarpetes: css, img, js, static. c. Un fitxer anomenat readme.md que contingui: i. A la primera línia «#Documentació del projecte» ii. A la segona línia la **data d’avui.v iii. La tercera línia el nom de l’usuari.
Si el nom de la carpeta existeix mostrarà un missatge d’avís i no la crearà.
ExCreaprojecte.sh
#!/bin/bash
if [
then
NOW=
else
if [
then
else
fi
En aquest script hem posat a prova tot el que hem après anteriorment.
Provem les 3 casuïstiques:
- Què passa si no li passem cap carpeta
- Si li passem carpeta que no existeix (crea el projecte)
- Si li passem carpeta que existeix.
#Documentació del projecte
Sintaxi comparadors i comprovació atributs de fitxers.
Revisa aquest article per aprendre tots els possibles comparadors de condicions, com -gt. O verificadors d’atributs de fitxers com -f.
-https://atareao.es/tutorial/scripts-en-bash/condicionales-en-bash/
Instal·lació programari necessari.
En ocasions per a què un programa funcioni necessitem que l’equip de l’usuari tingui instal·lat algún programa que no ve preinstal·lat a la seva distribució.
Per exemple, per mostrar els directoris en forma d’arbre necessitarà el tree, o per baixar-se un fitxer d’Internet el curl.
Per estalviar-li feina, podem instal·lar-lo automàticament en cas que no el tingui:
#!/bin/bash
if ! ; then
&&
fi
Ja hauries de tenir el programa curl i la imatge .png descarregada.
Pot ser que consideris que forçar a l’usuari executar scripts que forcin la instal·lació de programari sigui invasiu, però aquesta és una pràctica molt habitual, per exemple per a desenvolupadors, que volen centrar-se que la seva web funcioni sense preocupar-se gaire en aspectes del sistema operatiu.
Per exemple gestors de llibreries Javascript com nvm o bun.
Programari distribucions diferents a les basades en Debian/Ubuntu
Si volem portar l’script en una distribució diferent a les que hem vist com és el cas de Fedora o Redhat totes les comandes haurien de ser igual excepte el bloc de l’apt.
Aquí tenim una mostra del que hauriem de fer per a què el nostre script també funcioni en aquestes distribucions, que també són populars.
if ; then
&&
elif ; then
else
Comprovació que un fitxer ja ha estat descarregat.
Si volem crear un programa que llegeixi informació d’algun fitxer amb molta informació i aquest ja l’hem descarregat prèviament, per estalviar temps i un accés innecessari a Internet (que gasta electricitat) ens anirà molt bé usar un condicional per a què:
Cas 1.1 En el cas que el fitxer no el tinguem al disc el descarregui.
Cas 1.2 Si el fitxer ja l’hem descarregat abans (ho podem saber pel nom) no el descarregui.
Cas 2 En qualsevol dels 2 casos hauria de mostrar a l’usuari la informació del fitxer.
Exemple pràctic.
Volem crear un programa que descarregui una seqüència d’Uniprot passada per paràmetre i mostri per pantalla el seu contingut (el format d’aquestes comença per P, per exemple P12345) i es baixaran en format .fasta
Si ja s’ha descarregat abans no cal que ho faci.
Si l’usuari no envia cap identificador el programa avisarà un text com aquest: “❌ Ús: $0 <UniProt_ID>” i es tancarà.
La URL on es pot descarregar qualsevol proteïna pel seu UNIPROT_ID té la següent forma:
URL="https://rest.uniprot.org/uniprotkb/.fasta"Aquí tenim una solució completa a aquest problema:
#!/bin/bash
# Comprova si s'ha proporcionat un ID
if [; then
fi
# Instal·la el curl per baixar la proteïna si l'usuari del SO no el té.
if ! ; then
&&
fi
# Identificador de la proteïna
UNIPROT_ID=""
# Nom del fitxer de sortida
OUTPUT_FILE=".fasta"
# URL d'UniProt per descarregar en format FASTA
URL="https://rest.uniprot.org/uniprotkb/.fasta"
# Comprovar si el fitxer ja existeix
if [; then
else
# Comprovar si la descàrrega ha estat exitosa
if [; then
fi
fi
# Mostrar el contingut del fitxer
I els resultats que evidencien que funciona:
||
||
2. Crea un script que realitzi una còpia de seguretat i comprimeixi tots els fitxers i directoris d’un directori passat per paràmetre per l’usuari (pex. /home/$USER/projecte ) sempre cap a la ruta destí /home/$USER/Documents.
El nom de la còpia ha de contenir el dia actual. Pots usar aquest codi per aconseguir-la:
NOW={% sol %}
#!/bin/bash
# Comprovar si s'ha proporcionat el nom de la carpeta
if [; then
fi
# Carpeta on es vol fer la còpia
BACKUP_DIR=""
# Comprovar si la carpeta ja existeix
if [; then
fi
# Generar nom de la còpia amb data
NOW=
BACKUP_NAME="_"
# Crear còpia de seguretat
SOURCE_FOLDER="/home//Documents/"
# Comprovar si la còpia s'ha creat correctament
if [; then
else
💡 Exemple d’ús
Si no passes cap argument:
❌ Has d'introduir el nom de la carpeta on vols posar la còpia de seguretat.
🔹 Ús: ./backup.sh <nom_de_la_carpeta>Si la carpeta ja existeix:
ℹ️ La carpeta 'copia_segur' ja existeix. No es crearà una nova còpia.Si la còpia es fa correctament:
📂 Creant còpia de seguretat amb el nom: copia_segur_25_02_2025.tar.gz
✅ Còpia de seguretat completada: copia_segur_25_02_2025.tar.gz{% endsol %}
Bucles.
Per a repetir la mateixa instrucció un número determinat de vegades usem els bucles.
Podem usar el bucle for o el while
El bucle for en Bash és una mica diferent als bucles for tradicionals d’altres llenguatges com a C o Java, sinó que s’assembla més al bucle for each d’altres llenguatges com Python, ja que ací no es repeteix un nombre fix de vegades, sinó que es processen les paraules d’una frase una a una.
La seua sintaxi és la següent:
for
do
Un exemple d’aquest bucle l’hem vist al principi de tot; el fitxer hacking.sh:
#!/bin/bash
for
do
done
Un altre exemple senzill és aquest programa, que simula les tirades d’un dau. El nombre de vegades a tirar el dau se li ha de passar per teclat.
#!/bin/bash
for
do
dau=
En canvi, un exemple del while pot ser la lectura de fitxers amb la extensió fasta:
#!/bin/bash
for; do
3. Crea un shell script que realitzi un sorteig entre els 13 nans de la novel·la The Hobbit per tal de saber qui s’enfrontarà al drac Smaug.
Disposarem del nom del 13 nans en un fitxer anomenat nans i amb el nom de cadascú a una línia diferent
nans.txt
Thorin
Balin
Glóin
Bifur
Bofur
Bombur
Dwalin
Ori
Dori
Nori
Óin
Kíli
FíliQuan executem el script la sortida # haurà de ser del tipus:
{% sol %}
Ex2Tolkien.sh
# Numero de nans dintre del fitxer `
num_nans=
# num_nans = 13
# Sorteig... Numero aleatori
aleat=
nan=
{% endsol %}
🖥️Funcions en Bash
Les funcions en Bash permeten modularitzar el codi i reutilitzar-lo fàcilment. A continuació, es mostren dos exemples:
🔹 Funció sense arguments
Aquesta funció mostra la data i l’hora actual.
#!/bin/bash
# Funció sense arguments
# Crida a la funció
📝 Explicació
- La funció
mostrar_datano rep cap argument. - Fa servir
dateper mostrar la data i l’hora en format llegible. - Es crida simplement amb
mostrar_data.
🔹 Funció amb 1 o 2 arguments
Aquesta funció saluda un usuari.
#!/bin/bash
# Funció amb 1 o 2 arguments
if [; then
fi
NOM=""
COGNOM="" # Opcional, buit per defecte
if [; then
else
fi
# Crides a la funció
📝 Explicació
saludarrep un o dos arguments.- Si no rep cap argument, mostra un missatge d’error.
- Si només es passa un nom, saluda amb aquest nom.
- Si es passen nom i cognom, saluda amb els dos.
COGNOM="${2:-}"assegura que no hi hagi errors si només hi ha un argument.
🎯 Exercici 4: Còpia de seguretat amb funció
Descripció: Escriu un script Bash que creï una còpia de seguretat d’una carpeta i li afegeixi la data actual. Si el fitxer ja existeix, ha de mostrar un missatge i no tornar-lo a crear.
#!/bin/bash
# Funció per fer la còpia de seguretat
if [; then
fi
FOLDER=""
if [; then
fi
NOW=
BACKUP_FILE="_backup_.tar.gz"
if [; then
fi
if [; then
else
fi
# Exemple d’ús
📝 Explicació
- La funció
fer_backuprep un argument obligatori (el directori a fer la còpia). - Comprova que el directori existeixi abans de continuar.
- Genera un fitxer
.tar.gzamb la data actual. - Si el backup ja existeix, avisa l’usuari i no el crea de nou.
- Fa servir
tar -czvfper comprimir la carpeta. - Gestiona errors per evitar problemes en l’execució.
💡 Prova-ho!
Executa-ho en un terminal:
Així aprens a modularitzar el teu codi amb funcions! 🚀
Recursos:
Segueix amb els exemples: