Introducció
Els condicionals permeten determinar quines instruccions s'han d'executar en un programa segons si el resultat d'una condició s'avalua a cert o a fals.
Una de les funcions més importants per les quals utilitzarem els condicionals serà per a poder validar la informació que ens introdueix l'usuari. Així, per exemple, si un script precisa d'1 argument haurem de comprovar que l'usuari hagi especificat 1 argument o donar un missatge d'error conforme la sintaxis no és correcte.
Sentència if - bash
Per a realitzar les condicions utilitzem la sentència if. El format bàsic de la sentència if és:
if [ condició ]
then
sentències a executar si condició és certa
else # inici del bloc else
sentències a executar si condició és falsa
fi # final sentència if
Condició
La condició en bash depèn de si estem comparant valors numèrics, cadenes de caràcters (strings) o bé treballem amb fitxers.
Condició amb valors numèrics
Amb la comparació numèrica tenim les següents possibilitats:
- més petit ( < ) : -lt (less than)
- més gran ( > ) : -gt (greater than)
- més petit o igual ( <= ) : -le (less or equal)
- més gran o igual ( >= ) : -ge (greater or equal)
- mateix valor ( = ) : -eq (equal)
- valors diferents ( != ) : -ne (not equal)
Exemples
#!/bin/bash
if [ 3 -le 5 ]
then
echo "3 és menor que 5!"
fi
Nota: per tal que la sintaxis de la comanda if sigui correcte cal que hi hagi un espai després de l'obertura del corxet "[" i un espai abans del seu tancament "]"
#!/bin/bash
if [ 3 -le 5] # Exemple no correcte!!!
then
echo "3 és menor que 5!"
fi
if [3 -le 5 ] # Exemple no correcte!!!
then
echo "3 és menor que 5!"
fi
if [ 3-le 5 ] # Exemple no correcte!!!
then
echo "3 és menor que 5!"
fi
Video - Bash - Comparació de valors numèrics amb la instrucció if
Comanda test
Per a saber si una determinada instrucció és verdadera o falsa podem utilitzar la comanda test. Aquesta comanda avalua una expressió booleana i ens retorna el resultat associat a la condició.
#!/bin/bash
if test 3 -eq 5
then
echo "true"
else
echo "false"
fi
En aquest cas, la comanda test substitueix la notació dels clàudators "[]".
Condició amb valors strings
Per a comparar strings utilitzarem el doble claudator "[[ condicio ]]" . Igual que amb les comparacions numèriques inclourem un espai abans i després dels clàudators més interns. En cas contrari, obtindrem un error d'execució. Cal tenir en compte que bash és "case-sensitive" i, per tant, un string amb majúscules i el mateix en minúscules són diferents.
Nota: Per algunes comparacions podem utilitzar també un clàudator ([]), però donat que la doble notació és més genèrica podem utilitzar sempre aquesta com a mètode de simplificació.
La comparació amb strings ens ofereix les següents possibilitats:
- més petit : <
- més gran : >
- més petit o igual : <=
- més gran o igual : >=
- mateix valor : == ( també podem utilitzar un sol = )
- valors diferents : !=
- str2 està contingut en str1 : "$str1" == *"$str2"*
Exemples
#!/bin/bash
str1="Hola"
if [[ "$str1" == "Hola" ]]
then
echo "Els dos strings són iguals"
fi
if [[ "$str1" == *"ola"* ]]
then
echo "El text 'ola' està contingut en $str1"
fi
Video - Comparació amb strings
Condició amb fitxers
Sovint és important poder saber si una referència a un fitxer o directori és correcte, o els permissos associats a un determinat fitxer. bash script incorpora diferents operadors relacionats amb la seva existència, tamany o permisos:
-d FITXER FITXER existeix i es un directori.
-e FITXER FITXER existeix.
-r FITXER FITXER existeix amb permisos de lectura
-w FITXER FITXER existeix amb permisos d'escriptura
-x FITXER FITXER existeix amb permisos d'execució
-s FITXER FITXER existeix i no és buit
Exemples
Les precaucions que cal tenir alhora de determinar si un fitxer existeix o no existeix en el sistema són les mateixes que en les condicions anteriors, però en aquest cas només tindrem un operador (-d, -e, ...) i un nom del fitxer: normalment introduït per l'usuari.
#!/bin/bash
if [ -e "/home/miquel" ]
then
echo "/home/miquel existeix en el sistema"
fi
El codi anterior ens verifica si existeix un fitxer o directori de nom /home/miquel en el sistema. En cas afirmatiu hem d'utilitzar l'opció -d per a saber si és un directori. En cas contrari, només pot ser un fitxer.
Video - utilitzant if amb fitxers
Les opcions -r, -w, -x fan referència als permisos que té l'usuari que executa el script respecte al fitxer que es referencia. Si tenim un fitxer de nom exemple.dat amb permisos 770, la condició "-r exemple.dat" no podem afirmar que s'avalui a "True"; dependrà de l'usuari que executi la comanda. Si el fitxer no existeix, la condició s'avalua a "False".
Video - Comprovació permisos d'un fitxer
Sentencia elif
Quan hi ha moltes condicions if then else anidades, un dels problemes que hi ha és que cal tancar cada un dels if anidats. Podem simplificar el nostre codi utilitzant la sentència "elif" enlloc de "else if". L'avantatge de l'utilització de "elif" és que no cal tancar el bloc elif amb un if.
#!/bin/bash
if [ $1 -eq 1 ]
then
echo "Opció 1"
else
if [ $1 -eq 2 ]
then
echo "Opció 2"
else
if [ $1 -eq 3 ]
then
echo "Opció 3"
else
echo "Opció no vàlida"
fi
fi
fi
Podem simplificar el codi anterior utilitzant elif.
#!/bin/bash
if [ $1 -eq 1 ]
then
echo "Opció 1"
elif [ $1 -eq 2 ]
then
echo "Opció 2"
elif [ $1 -eq 3 ]
then
echo "Opció 3"
else
echo "Opció no vàlida"
fi
Operadors booleans
Quan es realitzen condicions, moltes vegades és necessari comprovar si una o vàries condicions són certes de forma conjunta. Per a poder enllaçar les condicions precisem dels operadors booleans ( i / o ).
Operador i
El resultat de dues condicions enllaçades per l'operador "i" és certa només si les dues condicions són certes per separat. En bash utilitzem el símbol "&&" per a unir dues condicions amb l'operador "i"
Exemple
#!/bin/bash
if [ $1 -eq 1 ] && [ $2 -eq 1 ]
then
echo "El primer i el segon argument tenen el valor 1"
fi
Operador o
El resultat de dues condicions enllaçades per l'operador "o" és certa si alguna de les dues condicions són certes per separat. En bash utilitzem el símbol "||" per a unir dues condicions amb l'operador "o".
Exemple
#!/bin/bash
if [ $1 -eq 1 ] || [ $2 -eq 1 ]
then
echo "Almenys un dels arguments té el valor 1"
fi
bash- Sentència case
Quan hi ha moltes condicions a avaluar i diferents accions a realitzar per a cada una d'elles, una bona opció és utilitzar una instrucció de tipus "switch", de forma que s'obté un codi més clar i fàcil de mantenir.
Sintaxis
La sintaxis de l'estructura "switch" és una mica diferent en el llenguatge bash que en la resta de llenguatges.
case <variable> in
<cas 1>)
<comandes>
;;
<cas 2>)
<commandes>
;;
...
;;
<cas N>)
<commandes>
*) # default
<comandes>
;;
esac
L'estructura de la sentència ens determina que hem d'utilitzar el nom de case; en la majoria de llenguatges és "switch". Cada bloc de cada un dels casos finalitza amb un doble ;; . Si tots els casos són falsos, s'executen les comandes del cas (tots els valors). Les sentències de també finalitzen amb ;;
Video - exemples sentència case
- Python - Sentència if
Python és un llenguatge que obliga a identar correctament les instruccions. Això vol dir que quan especifiquem les sentències que s'han d'executar, tant en el cas que la condició sigui certa o falsa, cal alinear les diferents sentències.
Python - Comparacions
A diferència de bash Python no diferencia els operadors per a comparar els valors numèrics o els strings. Els mateixos operadors són aplicables als dos tipus de dades. Els operadors de comparació de Python són:
- més petit : <
- més gran : >
- més petit o igual : <=
- més gran o igual : >=
- mateix valor : ==
- valors diferents : !=
- str2 està contingut en str1 : in ( str1 in str2 )
Cal tenir en compte que el tipus de dades és important per a la comparació. Així, per exemple, el valor numèric 11 és diferent al valor string "11". Per tant, cal realitzar una conversió per a fer les comparacions amb correcció.
Format sentència if
En el format de la sentència if, apart de la identació de cada una de les instruccions, es pot observar com la sentència THEN del bash ha quedat substituida pels ":" que indica el final de la condició. La sentència "else" també incorpora els ":" que obre el bloc de les sentències a executar si no es compleix la condició.
if condicio:
sentència1 cas true
sentència2 cas true
else:
sentència1 cas false
sentència2 cas false
Altres sentències fora del condicional
Video - Exemples amb sentència if
Python - Sentència switch
El llenguatge Python no incorpora la sentència switch. Per tant, cal utilitzar diferents condicions if per a simular la funcionalitat.
Python - accés a fitxers
Una de les primeres funcionalitats quan accedim a un fitxer utilitzant Python és la de comprovar si el fitxer o directori especificat existeix en el sistema. Per fer-ho, hem d'utilitzar la instrucció exists disponible en la llibreria os.path
#!/usr/bin/env python3
import os.path
if os.path.exists("/etc/passwd"):
print("El fitxer especificat existeix")
else:
print("El fitxer especificat no existeix")
Video - Comprovar si un fitxer existeix
Fitxer o directori
L'estratègia per a determinar si un nom donat es correspon a un fitxer o un directori és semblant a la que utilitzàvem en bash:
- Comprovar si el nom és vàlid (existeix)
- En cas que es cumpleixi el primer punt comprovar si és un directori "os.path.isdir(nomFitxer)".
- Si el segon punt és fals => és un fitxer
Permisos fitxers - Python
Per a comprovar els permisos d'un fitxer en Python el primer que hem de fer és importar dues llibreries: la llibreria de sistema i la llibreria stat.
#!/usr/bin/env python3
import os
import stat
La llibreria "os" ens permet obtenir els permisos associats al fitxer. La llibreria "stat" ens facilita diferents constants que ens permeten determinar quins són els permisos del fitxer. Per a obtenir un determinat permís, cal realitzar una operació AND bit a bit entre els permisos reals del fitxer i la màscara associada al permís. Utilitzem un exemple per a entendre el funcionament.
Exemple càlcul de permisos
Suposem que tenim un fitxer amb permisos 600 (octal) i volem determinar si el propietari del fitxer té permís de lectura.
Pas 1: Convertim a octal: 110 000 000
Pas 2: Màscara permisos de lectura: 400 (octal)
Pas 3: Convertim màscara a octal: 100 000 000
Pas 4: Apliquem operació "AND" (&) bit a bit
110 000 000 (Permisos fitxer)
& 100 000 000 (Màscara de lectura)
100 000 000 (Resultat operació)
Pas 5: Comprovar si el resultat obtingut coincideix amb el de la màscara aplicada. En cas afirmatiu, el permís està associat al fitxer, en cas negatiu, el fitxer no té el permís analitzat. Com podem comprovar, el resultat obtingut (Resultat operació) i la "Màscara de lectura" corresponen al mateix valor i, per tant, l'usuari propietari té el permís de lectura.
#!/usr/bin/env python3
#!/usr/bin/env python3
import os
import stat
mode = os.stat("testFile")
print("Permissos en mode octal: ",oct(mode.st_mode)) # 3 últims dígits
# Utilitzem constant S_IRUSR de la llibreira "stat"
lectp = mode.st_mode & stat.S_IRUSR
if lectp == stat.S_IRUSR:
print("Permís de lectura pel propietari")
else:
print("Sense permís de lectura pel propietari")
Del codi anterior hi ha dos aspectes importants que cal tenir en compte:
- Si el fitxer té el permís que s'està comprovant el resultat de l'operació "AND" ( & ) és la pròpia constant utilitzada.
- Les constants necessàries per a poder adaptar el codi són:
Constant | Valor | Descripció |
---|---|---|
S_IRWXU | 00700 | obtenir permissos propietari fitxer |
S_IRUSR | 00400 | propietari permissos de lectura |
S_IWUSR | 00200 | propietari permissos de escriptura |
S_IXUSR | 00100 | propietari permissos de execució |
S_IRWXG | 00070 | obtenir permissos grup fitxer |
S_IRGRP | 00040 | grup permissos de lectura |
S_IWGRP | 00020 | grup permissos de escriptura |
S_IXGRP | 00010 | grup permissos de execució |
S_IRWXO | 00007 | obtenir permissos altres fitxer |
S_IROTH | 00004 | altres permissos de lectura |
S_IWOTH | 00002 | altres permissos de escriptura |
S_IXOTH | 00001 | altres permissos de execució |
Video - determinar permissos fitxers
Exercicis
- Donat un nom de fitxer que l'usuari t'envia com a argument del programa comprova si aquest fitxer existeix o no en el teu sistema.
- Amplia l'exercici 1 especificant si l'argument introduït és un fitxer o un directori.
- Amplia l'exercici 2 de forma que si l'usuari no introdueix cap argument en la crida del programa, mostri el missatge: "Usage: nom.sh filename" . On nom.sh sigui el nom del teu script. Si es canvia el nom del script, també s'ha de canviar (automàticament) el missatge d'error.
- Amplia l'exercici 2 de forma que si l'usuari no especifica cap argument li demani el programa quan s'executi.
- Amplia l'exercici 5 de forma que si l'usuari especifica més d'un paràmetre li mostri com ha d'utilitzar el programa.
- Amplia l'exercici 5 de forma que si el fitxer especificat és un directori comprovi si l'usuari disposa de permís d'execució. En cas afirmatiu , el programa mostrarà té permís per accedir al directori (nom del directori). Sinó, cal mostrar un missatge conforme l'usuari no té accés al directori.
- Donat dos fitxers heu de dir quin dels dos ocupa més bytes o si són iguals. Per fer-ho heu d'utilitzar la comanda wc i la comanda cut. Per a igualar una variable a una comanda utilitzeu la forma var=$(comanda) . Per exemple: AVUI=$(date) guarda la data d'avui a la variable AVUI.
- Modifica l'exercici 7 reportant en un fitxer /var/log/nomprograma.err els errors que puguin succeir: "DATA: no existeix el fitxer X especificat" , on DATA és la data d'execució i X és el nom del fitxer. Si es canvia el nom del programa (nomprograma.sh) també haurà de canviar el nom del fitxer .err amb el nou nom.
- (MyEditor) Fes un programa que visualitzi un menú amb 4 opcions possibles. (1.- Crear un fitxer, 2.- Escriure text al fitxer, 3.- Veure contingut del fitxer, 4.- Modificar el fitxer, 5.- Sortir) . L'usuari haurà de començar sempre per l'opció 1. L'opció 2 sempre afegirà el text al final del fitxer, l'opció 4 demanarà una línia a l'usuari que serà la posició on vol insertar el text. Les opcions 2 i 4 han de demanar el text a inserir a l'usuari.