Desenvolupament de Funcions pels Sistemes Informàtics
ASI-2
GNU/Linux
Scripts de l'interpret d'ordres bash de GNU/Linux (I)
25/09/08

Scripts o arxius de guió de de l'interpret d'ordres bash de GNu/Linux(I)

1- Definició de variables del shell: =, $, set i unset
Són variables definides per l'usuari des del shell de Linux, i que poden ser utilitzades en qualsevol moment per guardar dades que li facilitin el seu treball en ser cridades per exemple dins d'una ordre Linux.
Una variable ha de definir-se abans de poder ser utilitzada, donant-li un nom i a que és igual. El nom d'una variable ha de complir les següents normes: a) Ha de incloure lletres o números o _ b) No pot començar amb un número c) No admet els caracters &, ! i espai en blanc d) No pot tenir més d'una paraula.
Una variable es defineix així

nom_variable=valor_variable.
Exemple:
nom=hola.

Per cridar al contingut d'una variable s'ha posar al davant el signe $. Si ara escrivim echo $nom, veurem per pantalla la paraula hola.Si fem que dirusr=/home/usuari, llavors cd $dirusr ens portarà al directori /home/usuari.
Amb l'ordre set llistem les variables que hem definit i les que Linux té definides per defecte quan s'inicia el sistema.
Amb l'ordre unset podem esborrar el valor al qual ha estat igualat una variable. Per exemple unset dirusr esborra el valor de dirusr (deixa dirusr en blanc).

2- Varables de sistema i delimitadors de cadenes.
A una variable de sistema li podem passar qualsevol cadena de caracters, que pot tenir com origen tant el fitxer standard d'entrada (el teclat) com el resultat d'una ordre. Alguns d'aquests caracters són especials i cal delimitar-los, i d'altra banda cal també delimitar quan estem passant una ordre o una simple cadena de caracters (no és el mateix voler igualar una variable al resultat que dóna la instrucció ls que voler igualar la mateixa variable a la cadena ls tractada simplement com una paraula de dues lletres). Els delimitadors utilitzats són els següents: a) Cometes b) Apòstrof( invertits i no invertits) c) Contrabarra \.
Els caracters especials amb els quals podem tenir problemes i cal delimitar són els següents: ? * . [] & $ i l'espai en blanc.
a) Delimitació de caracters amb Cometes.
Poden delimitar tots els caracters especials, menys $.Exemple:
name=Pere
nom="Hola, soc $name"
echo $nom

Per pantalla sortirà => Hola, soc Pere
b) Apòstrof no invertit.
Delimiten tots els caracters, inclòs $. Exemple:
name=Pere
nom='Hola, soc en $name'
echo $nom

Per pantalla sortirà => Hola, soc en $name
c) Contrabarra \
Delimita només un carácter especial (el que troba després de la contrabarra). Exemple:
name=Pere\ Carbonell (delimita l'espai en blanc)
premi=1000\$ (delimita $)
missatge="En $name ha guanyat $premi"
echo $missatge

El resultat serà => En Pere Carbonell ha guanyat 1000$.
d) Apòstrof invertits.
Serveixen per delimitar el resultat d'una ordre, es a dir, fan que la variable s'iguali al resultat de l'execució d'una ordre. Exemple:
listusr=`ls  -ls  /home/usr`
echo $listusr

Sortirà per pantalla => Llistat dels fitxers que hi han al directori /home/usr.
Veiem doncs, que els apòstrofs invertits forcen a executar primer l'ordre i després a igualar el resultat a la variable de sistema.

3-  Els arxius de guió o scripts del shell.
Un arxiu de guió o script és un arxiu de texte on s'han escrit i agrupat una o més ordres del shell de Linux en l'ordre que utilitzariem si les executessim una per una des del shell. La finalitat d'utilitzar arxius de guió és la de crear programes que ens permetin automatitzar treballs, de manera que puguem estalviar temps i disminuir el risc d'quivocació.  Creant un arxiu de guio, de fet, estem definint una nova ordre del Linux.
Un arxiu de guió és equivalent a un arxiu de processament per lots (arxius BAT) del dos, tot i que no cal que tingui obligatoriament una determinada extensió (de fet, no cal que tingui extensió, si així ho desitgem). D'altra banda els arxius de guió són la base de la configuració d'un sistema amb Linux i per tant molt més importants que els fitxers BAT.
Per crear un arxiu de guió del shell, tenim dos camins: a) Utilitzar l'ordre cat b) Treballar amb un editor de texte (ASCII). La primera opció només es vàlida per arxius de guió molt petits i senzills. Pels casos més complexes i llargs, hem d'utilitzar un editor de texte, com per exemple els editors joe, vi o emacs que sempre es troben presents a totes les distribucions Linux. Tot i que vi o emacs són més complets, joe és ideal per la seva senzillesa de manegament per crear arxius de guió del bash. Les seves principals ordres es poden veure permanentment a la pantalla, utilitzant la comanda Ctrl+K H un cop hem entrat dins de l'editor. Per cridar a aquest editor simplement hem d'utilitzar la comanda joe. Des de l'entorn gràfic podem utilitzar els editor kate, kedit o gedit.
3.1- L'ordre chmod
Un cop hem creat un arxiu de guió, l'hem de fer executable perquè realment s'utilitzi com una ordre del Linux. Això es fa amb l'ordre chmod de la següent manera:

chmod 777 nom_arxiu_guió
3.2- Pas de paràmetres en línia
Si volem passar un paràmetre en línia a un arxiu de guió, hem d'utilitzar l'argument $ seguit de la posicío del paràmetre dins de la línia ($1 pel primer paràmetre, $2 pel segon i així succesivament). Per exemple, el següent fitxer de nom lstusr imprimeix per pantalla els fitxers del directori /home/nom_directori amb l'extensió indicada, passant com a paràmetres el nom del directori i l'extensió:
cd /home/$1
ls *.$2

Si volem veure tots els fitxers amb extensió gz del directori /home/pere, hauria de fer la crida: lstusr  pere  gz

4- echo
Escriu a continuació la cadena de caràcters que li passem com a paràmetre. Especialment útil per treballar amb fitxers de guió.

5- Variables especials del shell: # * ?
#   Nº d'arguments passats a un arxiu de guió.
*   Cadena d'arguments passats a un arxiu de guió.
>? Codi de retorn de l'última ordre executada. Si val zero, vol dir que no s'ha produit cap error executant l'ordre. Si és diferent de zero, és que s'ha produït un error.
Exemple. Si fem un programa de nom lstusr1,amb les següents instruccions:
ls -$1 /home/$2/*$3
echo $#
echo $*
echo $?

Quan faci la crida lstusr1  s  pere  gz llavors, sortirà un llistat de tots els fitxers amb extensió gz del directori home/pere, amb la seva mida, i a continuació el número 3, i després s pere gz, o sigui una cosa com:
lstusr s pere gz
29 /home/pere/index.gz
25 /home/pere/fitx0_comp_gz.gz
38 /home/pere/fitx1_comp_gz.gz
29 /home/pere/SCSI-HOWTO.gz
0
3
s pere gz

però, si el directori pere no existís, o l'opció fos incorrecta, llavors en comptes del 0, sortiria un 1. 

6- read
Tot allò que s'introdueixi des de teclat serà assignat a una variable. És equivalent a fer un cin o un scanf del llenguatge C. Si volem tractar els caràcters especials com per exemple $, *, ? / [ \ ] ( ) < > >>, com a caràcters normals , llavors els hem de delimitar amb cometes o cometes dobles. En cas contrari seran considerats com a caràcters especials. L'ordre read s'utilitza bàsicament dins d'arxius de guió del shell, tot i que també pot ser cridat directament des del shell.

Si volem executar un arxiu de guió que faci el mateix que hem vist a l'apartat anterior, però que demani a l'usuari les dades per teclat, farem el següent:
echo "Dona opció:"
read opcio
echo "Dona directori:"
read directori
echo "Dona extensió:"
read extensió
ls -$opcio /home/$directori/*.$extensio
echo $?
echo $#
echo $*

7- expr
Permet fer avaluacions d'una variable del shell. Les més importants són les següents: a) Aritmètiques b) Comparació de cadenes c) Longitud de cadenes.
7.1- Avaluació aritmètica
Si fem b=5, i després expr $b, llavors tindrem com a sortida 5. L'ordre ha avaluat el valor de b, i ens el dóna per pantalla. Si podem aconseguir un valor, llavors, també podem fer operacions amb aquest valor. Les operacions són +   -   /   "*"  "<"  ">"  "<="  ">="  "!="  "==".

Exemple 1
a=4
b=5
c=`expr $b + $a`
echo $c

9

Exemple 2
a=4
b=5
c=`expr $b ">=" $a`
echo $c

1 (és veritat)

7.2- Avaluar la part comuna de dues cadenes de caràcters
Utilitzarem l'ordre expr amb l'opció :, que li permet comprovar si una cadena és una succedani d'una altra cadena model (començant des del primer caràcter) i trobar quants caràcters té en comú la subcadena amb la cadena model. Si la subcadena és de fer més gran que la cadena model, o és diferent a qualsevol lloc, el resultat és zero (0).
L'ordre és expr $a : $b on $a és la cadena model i $b és la subcadena.

Exemple:

a=paraula
b=pa
expr $a : $b

2

a=paraula
b=pa
expr $a : $b

0

a=paraula
b=pa
expr $a : $b

0

a=paraula
b=pa
expr $a : $b

0


7.3- Longitud d'una cadena
Aprofitant el que hem vist a l'apartat anterior, faríem el següent:
a=paraula
expr $a : $a

7

i també hi ha l'opció lenght, de manera que:
a=paraula
expr length $a
7

8-  test
Permet compara cadenes senceres i números. També permet comparar fitxers.
8.1- Avaluació directa de cadenes
Compara dues cadenes, i si el resultat de la comparació demanada és cert, dins de la variable ? tindrem un 0, i si no és cert, tindrem un 1.
Tipus de comparacions: " <"  ">"   =   !=
Exemples:

a=hola

b=adeu

c=hola

test $a = $b

echo $?

1

a=hola

b=adeu

c=hola

test $a "<" $b

echo $?

1

a=hola

b=adeu

c=hola

test $a ">" $b

echo $?

0

a=hola

b=adeu

c=hola

test $a = $c

echo $?

0

a=hola

b=adeu

c=hola

test $a != $b

echo $?

0

8.2- Avaluació de valors numèrics
Igual que a l'apartat 5.1, però les ordres de comparació són:
a) -lt
(Més petit que) 
b) -le
(Mes petit o igual que) 
c) -gt
(Més gran que) 
d) -ge
(Més gran o igual que)
e) -eq (Igual que)
f) -ne
(No igual que)
Exemple:
a=4
b=3
test $a -gt $b

0

8.3- Avaluació de fitxers
Té moltes opcions. Millor anar a el manual amb man test. Una de les opcions més important és -e que ens permet saber si un fitxer existeix o no.
Exemple: test  -e  /camí_al_fitxer/nom_fitxer
Si existeix, ens retorna 0 dins de la variable ?, i un 1 si no existeix.

Una altra opcio important és -s que retorna un 0 dins de la variable ? si un fitxer existeix i té una mida diferent a zero bytes.
Amb l'opció -d, ens diu si existeix el fitxer o no existeix, i si és un directori o no. Ens diu que és veritat (0 a la variable ?)si existeix i és directori.

8.4- Opcions -a, -o i !
Fan les operacions lògiques AND (-a), OR (-o) i NOT (!) amb els resultat de dues avaluacions.

Exemple:

x=5

y=6

z=7

test  $x -ge $y  -a  $z -gt  $x

1

x=5

y=6

z=7

test $x -ge $y -o $z -gt $x

0

9- Ordre if-then-else-fi
Comprova si una ordre ha estat executada amb èxit o si una expressió és correcta. En cas de que el resultat de la comprovació sigui veritat, executa una sèrie d'ordres, i si és falsa, n'executa unes altres. Funciona bàsicament igual que if-else de C. L'ordre then és equivalent a { i l'ordre fi a }. També permet avaluar l'èxit o fracàs de l'execució d'una ordre del bash shell.

Estructura:
if ordre_o_expressió_linux
then
    ordre_linux_1
    ordre_linux_2
    ordre_linux_3
    ....................

else
    ordre_linux_N
    ordre_linux_N+1
     ....................

fi

Exemple:
Fes un arxiu de guió que ens permeti fer un llistat del directori en el qual es troba l'usuari, amb dues opcions: a) Veure mida dels fitxers b) Veure totes les característiques dels fitxers.
echo "Escriu s per llistar el directori amb la mida dels arxius"
echo "Escriu l per llistar totes les característiques dels arxius"
read opc
if test $opc == "s"
then
    ls -s
else
    ls -l
fi

10- Ordre case-in-esac
a)
Permet escollir entre des o mes camins d'execució d'ordres alternatius.
b)
La selecció es fa comparant un valor_comparat amb diversos valors_de_comparació. Quan el valor_comparat coincideix amb un valor_de_ comparació, llavors, s'executen les ordres associades a aquest valor_de_comparació.
c)
L'equivalent a default de C, és *
d)
Sempre finalitza amb esac.

Estructura: 
case valor_comparat in
    valor_de_comparació_1)    ordre
                                                 ordre;;

    valor_de_comparació_2)    ordre
                                                 ordre
                                                ordre;;

    valor_de_comparació_3) ordre;;

    ..........................................
    ..........................................

    *) ordre_per_defecte
        ordre_per_defecte;;
esac

Exemple 1:
echo " a) Llistat del directori /home/pere"
echo " b) Llistat del directori /home/joan"
echo " c) Llistat del directori /home/anna"
echo " d) Llistat del directori /home/maria"
read opc
case $opc in
    a) ls -ls /home/pere;;
    b) ls -ls /home/joan;;
    c) ls -ls /home/anna;;
    d) ls -ls /home/maria;;
    *) echo "Opció incorrecta";;
esac

Exemple 2:
case "$1" in
     'start')
         /usr/app/startup-script
         ;;
     'stop')
         /usr/app/shutdown-script
         ;;
     'restart')
         echo "Usage: $0 [start|stop]"
         ;;
esac

11- Ordre while-do-done
Estructura:
while ordre_o_expressió_linux
do
    ordres_linux
done

Executa ordres_linux mentre es compleixi ordre_o_expressió_linux. Sempre acaba amb done. Abans d'entrar en el llaç s'avalua la condició d'entrada.

Exemple:
<Fitxer_càlcul_doble>
a=1
while
test $a -le 4
do
    b=`expr $a "*" 2`
echo $b
a=`expr $a +1`

done
echo "Adéu i fins una altra ocasió"

El resultat serà:
2
4
6
8
Adéu i fins una altra ocasió

Exemple 2
verifica="n"
while [ "$verifica" != y ]
do
    echo "Entra opció: "
    read opció
    echo "Has entrat l'opció  $option.  És correcte? (s/n)"
    read verifica
done

12- Ordre until-do-done
Estructura:
until condició
do
    ordres_linux
done

Executa ordres_linux, i s'executarà fins que no es compleixi condició no sortirem del llaç. Sempre acaba amb done. Abans d'entrar en el llaç no s'avalua la condició d'entrada.

Exemple:
a=5
until
test $a -le 4
do
    b=`expr $a "*" 2`
    echo $b
    a=`expr $a +1`

done
echo "Adéu i fins una altra ocasió"

a diferència de while, que no faria res en un cas com aquest, until s'executarà i no s'aturarà fins que $a sigui més petit o igual a 4, cosa que aquí no pot passar mai.

13- Ordre for-in do-done
Estructura:
for variable in llista
do
    ordres_linux
done
Funciona de la següent manera:
1r) Assigna a variable al primer valor de llista
2n) Executa ordres_linux
3r) Assigna variable al següent valor de la llista
4t) Executa ordres_linux
5è) Torna al 3r pas fins que s'acabin les variables de la llista.

Exemple 1:
for a in *.gz
do
    gzip -d $a
done
echo "Adéu i fins una altra ocasió"

Descomprimeix tots els fitxers amb extensió .gz que es trobin al directori de treball actual.

Exemple 2
for
a in 1 2 3 4
do
    b=`expr $a "*" 2`
echo $b
done

El resultat serà:
2
4
6
8

Exemple 3
#!/bin/sh
logfile="/var/log/messages"
for mon in Sun Mon Tue Wed Thu Fri Sat
do
   grep $mon $logfile > $logfile.$mon
done


El resultat serà un fitxer de log diferent per cada dia de la setmana, a partir del fitxer de log general /var/log/messages

14- Ordres break, continue i exit
a) break:
Finalitza un llaç until, while o for, i passa el control a primera ordre que es trobi després de la paraula clau done.
b) continue:
Atura until, while o for, i torna a començar de nou.
c) exit n:
Finalitza l'execució de l'arxiu de guió del bash shell, i assigna el valor n com a codi de retorn (que normalment serà un zero si tot ha anat bé, i un número diferent de zero en cas contrari).

PRÀCTICA

1- Crea un variable de sistema amb el nom list on guardis el camí /var/log. Des del teu directori canvia directament al directori /var/log utilitzant la variable list. També des del teu directori, fes un llistat dels fitxers d'aquest directori, utilitzant també la variable list.

2- Comprova amb l'ordre set el valor de list. Si no ho pots veure pots utilitzar l'ordre more amb el carácter de canalització. Esborra el valor de list i comprova que el valor ha estar realment esborrat.

3- Crea la variable nom, i fes-la igual al teu login. Crea una altra variable, amb nom lst, que sigui igual al contingut del llistat del teu directori. Per fer-ho, utilitza la variable nom. Finalment fes un echo de la variable lst i comprova el seu resultat.

4- Fes un programa del bash shell, de nom  p1s1.sh, que realitzi les següents tasques quan s'executi
a) Copiar el fitxer fstab que es troba a /etc al teu directori.
b) El canvia de nom. El nou nom serà fstab2.
c) El comprimeix.
d) Finalment realitza un llistat del teu directori personal.
NOTA 1: El nom del teu directori ho has de passar com a paràmetre en la línia d'ordres.

5- Fes un programa del bash shell que visualitzi per pantalla els números del zero al 100 i els seus quadrats.El nom del script serà p1s2.sh.

6- Fes una calculadora que faci les quatre operacions bàsiques (*,/,+ i -). El nom del script serà p1s3.sh.

7- Fes un programa del shell que "esborri" els fitxers que tinguin una determinada extensió, de manera que els poguem recuperar posteriormemt (en Linux, quan esborrem un fitxer, es perd definitivament). Per això, has de crear dins del teu directori personal, un subdirectori anomenat paperera dins del qual deixaràs els fitxers "esborrats". Els tipus d'arxius que volguem esborrar els passarem com arguments al programa shell. Amb l'opció -r esborrarem definitivament els fitxers de la paperera. Amb l'opció -e enviem els fitxers a la paperera. El nom del script serà p1s4.sh.

8- Fes un programa que ens demani un número per teclat fins que encertem un altre número que hem guardat previament dins d'una variable del shell. El programa finalitzarà quan encertem el número, i ens donarà la quantitat d'intents realitzats. El programa ens informarà per cada intent si el número donat és més gran o petit que el número guardat. El nom del script serà p1s5.sh.

9- Fes un script per l'usuari root, en el qual se li demanin totes les dades necessàries per crear un usuari. Un cop donades les dades, el programa crearà l'usuari. El nom del script serà p1s6.sh.

10- Fes un script per l'usuari root, en el qual se li demanin totes les dades necessàries per esborrar un un usuari. Un cop donades les dades, el programa esborrarà l'usuari. El nom del script serà p1s7.sh.

11- Fes un script per l'usuari root, en el qual se li mostri un menú on pugui escollir executar qualsevol dels scripts demanats als apartats 9 i 10 tantes vegades com ho volgui. El nom del script serà p1s8.sh.

12- S'han de lliurar els arxius de guió comprimits dins d'un arxiu de nom asi2_dfsi_nom_cognom_p1_linux.tar.gz que s'han d'enviar a cf(arrova)collados.org.  A l'assumpte del correu heu de posar asi2_dfsi_nom_cognom_p1_linux. L'últim dia per lliurar el treball és el 30-10-2008. Cada dia que passi d'aquesta data, treuré dos punts a la nota del treball.

Informació complementària per fer els arxius de guió p1s6.sh, p1s7.sh i p1s8.sh
Administració bàsica d'usuaris des de l'interpret d'ordres del bash shell