Sunteți pe pagina 1din 23

1.

Bourne Again Shell

BOURNE AGAIN SHELL

8.1 Introducere Bourne Again Shell (bash) ofer o serie de faciliti n plus fa de shell-ul standard Bourne, att la nivel de interpretor al liniei de comand, ct i la nivel de limbaj de programare. Printre altele, bash ofer istoric al comenzilor, alias-uri, auto-completarea comenzilor i a numelor de fiiere, editarea liniei de comand, etc. Unele dintre aceste faciliti sunt prezente i n shell-ul standard Bourne, ns proiectul GNU a extins shell-ul pentru a include un numr de noi faciliti i pentru compatibilitate POSIX. O dat cu realizarea variantei bash 2.x, au fost adugate att de multe funcionaliti (unele din Korn shell i C shell), nct shell-ul bash reprezint un shell complect funcional att la nivel de interpretor ct i la nivel de limbaj de programare. Shell-ul bash s-a nscut pe 10 ianuarie 1988 sub oblduirea lui Brian Fox i a fost adoptat mai trziu de ctre Chet Ramey. Prima versiune a fost versiunea bash 0.99, iar cele mai importante mbuntiri au fost aduse odat cu versiunea 2.0. Toate versiunile sunt disponibile free sub licen public GNU. Pentru a vedea ce versiune de bash folosete, un utilizator poate folosi comanda bash --version sau poate afia valoarea variabilei de mediu BASH_VERSION. Urmtorul exemplu ne nfieaz o posibil situaie:
$ bash --version GNU bash, version 2.04.11(1)-release (i386-redhat-linux-gnu) Copyright 1999 Free Software Foundation, Inc. $ echo $BASH_VERSION 2.04.11(1)-release

UNIX

8.2 Iniializare i mediu n momentul iniializrii, shell-ul bash parcurge o serie de pai. Primul proces ce se ruleaz n momentul iniializrii este init, cu identificatorul PID=1. Acest proces iniiaz un proces getty, care deschide porturile terminalului, oferind un spaiu de manevr pentru standard input i pentru standard output i standard error. n urma acestui proces va fi afiat un prompter de login pe ecran. n continuare se execut programul /bin/login, care cere o parol, cripteaz i verific parola, setnd un mediu iniial de lucru i pornind shell-ul de login (care n cazul nostru este /bin/bash). Dup aceea, procesul (programul) bash caut fiierul de configurare /etc/profile i execut comenzile din acesta. n continuare, se caut n directorul home un fiier de configurare iniial denumit .bash_profile. Dup executarea comenzilor din acest fiier, se va executa o comand din fiierul ENV al utilizatorului, de regul .bashrc i, n cele din urm, prompter-ul (semnul $ pentru utilizatorul obinuit sau # pentru root) este afiat pe ecran, ateptnd introducerea de comenzi. Dac dorim modificarea shell-ului la linia de comand, putem s introducem simplu numele shell-ului i s apsm ENTER. De exemplu, dac folosim la un moment dat shell-ul standard Bourne i dorim s schimbm n Bourne Again shell, nu avem dect s introducem bash la linia de comand, urmat de tasta ENTER:
$ ps PID TTY TIME CMD 5549 tty1 00:00:00 sh 5429 tty1 00:00:00 ps $ bash bash-2.04$ bash-2.04$ ps PID TTY TIME 5449 tty1 00:00:00 5465 tty1 00:00:00 5472 tty1 00:00:00

CMD sh bash ps

Explicaii. Iniial, comanda ps (process status) ne arat procesele aflate n execuie. Se observ c ruleaz shell-ul Bourne (sh). Se introduce apoi comanda bash la prompter i apare un nou prompter (bash-2.04$).

Bourne again shell

Introducnd din nou comanda ps, se afieaz de data aceasta dou shell-uri care ruleaz: shell-ul iniial sh i shell-ul bash pornit ulterior. Fiiere de iniializare Shell-ul bash are o serie de fiiere de configurare pe care le verific la pornire. Aceste fiiere de configurare sau iniializare sunt procesate (rulate) n funcie de mai multi factori (dac shell-ul curent este i shell-ul de login, dac este un alt shell interactiv diferit dect cel de login, sau un shell non-interactiv - shell-script). S vedem n continuare care sunt fiierele de configurare iniial i ordinea n care aceste fiiere sunt procesate. n momentul login-ului, nainte de apariia prompter-ului shell, este executat fiierul de configurare global, /etc/profile. Dup aceea, dac exist, este procesat fiierul .bash_profile din directorul home al utilizatorului. Acest fiier specific alias-uri i funcii i seteaz variabile de mediu specifice utilizatorului sau pornete anumite shell-script-uri. Dac fiierul .bash_profile nu exist, dar exist fiierul .bash_login, atunci acest fiier va fi procesat, iar dac acesta din urm nu exist, va fi procesat fiierul .profile (din directorul home al utilizatorului).

8.2.1 Fiierul /etc/profile Fiierul /etc/profile reprezint un fiier de configurare global a ntregului sistem. Acest fiier este editat de ctre administratorul sistemului pentru a executa anumite comenzi atunci cnd se iniializeaz sistemul. El este executat atunci cnd pornete shell-ul bash. El are acelai efect i n cazul shell-urilor Korn i Bourne i, de regul, ndeplinete anumite sarcini precum rularea programului ce administreaz mailul (mail spooler) sau afiarea unui mesaj iniial, denumit mesajul zilei (message of the day, din fiierul /etc/motd). n continuare este prezentat un exemplu de fiier /etc/profile (nu am numerotat liniile goale):
1 #/etc/profile 2 # System wide environment and startup programs 3 # Functions and aliases go in /etc/bashrc 4 PATH=$PATH:/usr/X11R6/bin 5 ulimit -S -c 1000000 > /dev/null 2>&1 6 if [ id -gn = id -un -a id -u -gt 14 ]; then 7 umask 002 8 else

UNIX 9 10 11 12 13 14 15 umask 022 fi USER=id -un LOGNAME=$USER MAIL=/var/spool/mail/$USER HOSTNAME=`/bin/hostname` HISTSIZE=1000

16 if [ -z $INPUTRC -a ! -f $HOME/.inputrc ]; then 17 INPUTRC=/etc/inputrc 18 fi 19 export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE INPUTRC 20 for i in /etc/profile.d/*.sh ; do 21 if [ -x $i ]; then 22 . $i 23 fi 24 done 25 unset i

Prezentm n continuare cteva explicaii analiznd fiierul /etc/profile pe linii: Liniile 1,2,3 - Comentarii n shell-script; Linia 4 - Variabilei PATH i se atribuie directoarele unde va cuta shell-ul comenzile introduse; Linia 5 - Comanda ulimit stabilete limita maxim a dimensiunii fiierelor core la 1.000.000 bytes. Fiierele core sunt fiiere create n urma opririi anormale a programelor i pot ocupa dimensiuni considerabile din spaiul de pe disc; Liniile 6-10 - Comanda if care realizeaz urmtoarele: dac numele grupului este egal cu numele utilizatorului i numrul ID al utilizatorului este mai mare dect 14, atunci seteaz umask cu valoarea 002. n acest caz, atunci cnd sunt create directoarele vor avea drepturi de acces 775 iar fiierele vor avea 664. Altfel, umask va avea valoarea 022, de unde rezult drepturi 755 pentru directoare i 644 pentru fiiere. Linia 11 - Variabilei USER i se atribuie valoarea pe care o returneaz comanda id -un (numele utilizatorului) Linia 12 - Variabilei LOGNAME i se atribuie valoarea din $USER; Linia 13 - Variabila MAIL ia valoarea egal cu numele directorului unde se programul de administare a mail-ului va salva mail-ul; Linia 14 - Variabila HOSTNAME ia valoarea numelui mainii; Linia 15 - Variabila HISTSIZE ia valoarea 1000 (numrul de comenzi stocate n memoria history);

Bourne again shell

Liniile 16-18 - Comanda if care verific dac fiierul cu numele dat de variabila INPUTRC are dimensiunea diferit de zero i nu exist fiierul .inputrc din directorul home i n acest caz variabila INPUTRC ia valoarea /etc/inputrc; Linia 19 - Variabilele ce apar n aceast linie sunt exportate pentru a fi disponibile n sub-shell-uri i procese copil; Linia 20-24 - O comanda for i una if care realizeaz urmtoarele: pentru fiecare fiier cu extensia .sh din directorul /etc/profile.d, se verific dac este executabil, iar dac este executabil, se execut fiierul utilizndu-se comanda dot (.). Fiierele din directorul /etc/profile.d, lang.sh i mc.sh, seteaz setul de caractere i de fonturi i creaz o funcie denumit mc (Midnight Commander) care reprezint un browser (asemntor cu vestitul Norton Commander pentru DOS/Windows) vizual de fiiere. Pentru pornirea acestuia se scrie mc la linia de comand. Linia 25 - Variabila i este resetat prin comanda unset, adic tears din memoria shell-ului. 8.2.2 Fiierul .bash_profile Dac fiierul .bash_profile este gsit n directorul home al utilizatorului, atunci este executat imediat dup /etc/profile. Dac .bash_profile nu exist, atunci shell-ul bash va cuta fiierul .bash_login sau, dac nici acesta nu exist, fiierul .profile, toate din directorul home. Doar unul dintre cele trei fiiere menionate anterior va fi executat, iar cutarea se face n ordinea specificat (bash_profile, .bash_login, .profile). De asemenea, bash va verifica existena fiierului .bashrc i l va executa comenzile din acesta dac fiierul exist. Prezentm n continuare un exemplu de fiier .bash_profile:
1 #.bash_profile 2 # Get the aliases and functions 3 if [ -f ~/.bashrc ]; then 4 . ~/.bashrc 5 fi 6 PATH=$PATH:$HOME/bin 7 BASH_ENV=$HOME/.bashrc 8 USERNAME=razvan 9 export USERNAME BASH_ENV PATH 10 mesg n

UNIX

Prezentm n continuare cteva explicaii analiznd fiierul .bash_profile pe linii: Liniile 1,2 - Comentarii n shell-script; Liniile 3-5 - Comand if care verific dac fiierul .bashrc se afl n directorul home i dac exist l ruleaz; Linia 6 - Variabilei PATH i se adaug o cale ctre subdirectorul bin din directorul home; Linia 7 - Variabilei BASH_ENV i se atribuie valoarea specificat (calea ctre fiierul .bashrc). Fiierul .bashrc conine funcii i alias-uri definite de utilizator; Linia 8 - Variabila USERNAME ia valoarea razvan; Linia 9 -Variabilele specificate sunt exportate pentru a fi valabile n subshell-uri i procese copil; Linia 10 - Comanda mesg executat cu opiunea n are ca efect blocarea mesajelor primite cu comanda write de la ali utilizatori.

8.2.3 Fiierul .bashrc Fiierul .bashrc este automat executat ori de cte ori un shell bash pornete, coninnd numai setri valabile pentru shell-ul bash. Avem n continuare un exemplu de fiier .bashrc:
1 #.bashrc 2 # User specific aliases and functions 3 # Source global definitions 4 if [ -f /etc/bashrc ]; then 5 . /etc/bashrc 6 fi 7 set -o noclobber 8 alias mv=mv -i 9 alias dir=ls -al 10 function cd { builtin cd $1; echo $PWD; }

Explicaii: Liniile 1,2,3 - Comentarii n shell-script; Liniile 4-6 - Comand if care verific existena fiierului /etc/bashrc i n acest caz l ruleaz; Linia 7 - Comanda set apelat cu opiunea noclobber determin apariia unor mesaje preventive n cazul suprascrierii fiierelor deja existente;

Bourne again shell

Linia 8 - Se declar un alias pentru comanda mv, astfel nct de acum ncolo ea va fi apelat automat cu opiunea -i(interactive); Linia 9 - Se declar un alias pe nume dir, care va efectul apelului comenzii ls -al; Linia 10 - Se definete o funcie utilizator. Cnd utilizatorul va schimba directorul curent se va afia i directorul curent de lucru. Numele fucniei este cd i conine comanda intern cd (change directory). Comanda intern builtin precede numele comenzii cd pentru a preveni intrarea n recursivitate infinit a funciei. 8.2.4 Fiierul .profile Fiierul .profile este un fiier de configurare definit de utilizator. El se gsete n directorul home al utilizatorului i este executat imediat dac shell-ul de login este shell-ul Bourne. n cazul n care shell-ul de login este bash, fiierul .profile va fi rulat doar dac nici unul din fiierele enumerate anterior nu exist. Fiierul conine de regul setri ale mediului i ale terminalului sau alte setri legate de diverse aplicaii, dac acestea sunt necesare. Avem n continuare un exemplu de fiier .profile:
1 2 3 4 #.profile # Fisier de configurare initiala ce se executa atunci cand # se utilizeaza shell-ul sh sau nu exista fisierele # .bash_profile sau .bash_login

5 HOSTNAME=`uname -n` 6 EDITOR=/bin/vi 7 PATH=/bin:/usr/bin:/usr/ucb:/usr/local:/usr/bin:. 8 PS1=$HOSTNAME $> 9 export TERM HOSTNAME EDITOR PATH PS1 10 stty erase ^h 11 clear

Explicaii: Liniile 1-4 - Comentarii n shell-script; Linia 5 - Variabila HOSTNAME va lua valoarea returnat de comanda uname -n; Linia 6 - Variabila EDITOR ia valoarea /bin/vi. Programe precum mail i history vor folosi acest editor; Linia 7 - Variabila PATH este setat; Linia 8 - Prompter-ului primar i este atribuit valoarea lui HOSTNAME (numele mainii), urmat de semnul $ i semnul >;

UNIX

Linia 9 - Sunt exportate variabilele specificate, pentru a fi valabile n subshell-uri i procese copil; Linia 10 - Comanda stty seteaz caracteristicile terminalului. Tasta Erase este setat cu valoarea ^h, astfel nct cnd vom apsa tasta Backspace, litera de dinaintea cursorului va fi tears; Linia 11 - Comanda clear terge coninutul ecranului. 8.3 Programarea n bash Scrierea unui shell-script n bash este similar cu operaia n Bourne Shell. Un shell-script se scrie cu ajutorul unui editor i conine comenzi UNIX, comentarii i cuvinte cheie de programare shell. Deoarece utilizm shell-ul bash, prima linie din shell-script va fi:
#!/bin/bash

De asemenea, script-ul trebuie s fie executabil, de aceea vom folosi comanda chmod pentru a l face executabil. n exemplul urmtor presupunem c script-ul se numete script01:
$ chmod +x script01 $ ls -lF script01 -rwxr-xr-x 1 razvan

12 Aug 12:00

script01*

8.3.1 Citirea variabilelor Citirea variabilelor se face ca i n shell-ul clasic cu comanda read. Comanda read preia caractere de la tastatura pn cnd se ntlnete un caracter newline. Caracterul (newline) de sfrit de linie este transformat ntr-un octet null atunci cnd este citit. Dac nu se specific nici un nume pentru variabil, linia citit este atribuit unei variabile interne, numit REPLY. Putem, de asemenea, folosi comanda read pentru a face un program s se opreasc n momentul n care apsm tasta ENTER. Opiunile comenzii read sunt prezentate n tabelul 8.1. De exemplu, opiunea -r este folosit pentru ignorarea perechii backslash/newline, astfel nct caracterul special backslash este considerat ca parte din linie.

Bourne again shell

Opiunile comenzii read


Tabelul 8.1
Comanda read raspuns read r1 r2 read read -a nume_vector read -e read -p prompter read -r linie Semnificaie Se citete de la tastatur n variabila raspuns Se citete de la tastatur n variabila r1 pn la primul caracter whitespace sau Enter, apoi n variabila r2 Se citete n variabila intern REPLY Se citete o list de cuvinte ntr-un vector denumit nume_vector Se folosete n shell-ul interactiv Afieaz un prompter, ateapt input-ul i stocheaz rezultatul n variabila REPLY Permite introducerea liniilor ce conin un backslash

8.3.2 Operaii aritmetice Variabilele pot fi declarate ca numere ntregi cu ajutorul comenzii declare -i. O variabil numar poate fi declarat astfel:
$ declare -i numar

Se pot face operaiile aritmetice uzuale cu variabilele declarate ntregi, folosind operatorii pentru adunare, scdere, nmulire, mprire i mprire modulo. Exemple:
$ declare -i numar $ numar=3+7 $ echo $numar 10 $ numar= 6 + 9 bash: +: command not found (caracterele whitespace trebuie incadrate ghilimele, corect este: numar=6 + 9) $ numar=4*5 $ echo $numar 20

de

UNIX

Comanda declare -i fr nici un argument va lista toate variabilele ntregi definite, precum i valorile lor, ca n exemplul urmtor:
$ declare -i declare -ir EUID=0 declare -ir PPID=846 declare -ir UID=0 declare -i numar=20 $

Se pot utiliza numere reprezentate n baze de numeraie diferite, de la baza 2 la baza 36. Formatul general de reprezentare ntr-o anumit baz este:
variabila=baza#numarul_in_acea_baza

Spre exemplu, dac: nr=2#110, atunci avem numrul 110 reprezentat n baza 2. Se pot declara numere octale (n baza 8) dac valoarea numeric a acestora este precedat de un 0 (zero). De exemplu, dac avem comanda: declare -i nr=020, atunci variabila nr are valoarea zecimal 16. Comanda let Comanda let este o comand intern bash utilizat pentru a realiza operaii aritmetice cu ntregi i a testa expresii numerice. Operatorii care sunt acceptai de comanda let pot fi vizualizai cu ajutorul comenzii: help let. Numere reale Shell-ul bash ofer suport doar pentru operaii cu numere ntregi; dac avem de fcut calcule cu numere reale, putem folosi utilitarele bc, awk sau nawk. Exemple:
$ nr=`echo scale=2; 12 / 5 | bc` $ echo $nr 2.40 $ p=`gawk -v x=2.2 -v y=3.3 BEGIN{printf %.2f\n,x*y}` $ echo $p 7.26

Bourne again shell

8.3.3 Parametri poziionali i comanda set Parametrii poziionali sunt aceeai cu cei din Bourne Shell: $0 este numele script-ului, $1-$9 reprezint valorile parametrilor poziionali iar $* listeaz toi parametrii poziionali. Dac numrul parametrilor poziionali era restrns la 9 pentru shell-ul Bourne, n bash putem folosi ci parametri poziionali dorim. Pentru valori mai mari dect 9, ei vor fi referii astfel: ${10}, ${11}, etc. $* semnific extinderea la un singur argument, de genul: $1 $2 $3, iar $@ are semnificaia: $1 $2 $3. Considerm urmtorul exemplu:
#!/bin/bash #Numele script-ului este test echo Numele script-ului este $0 echo Primul parametru pozitional este $1 echo Al doilea parametru pozitional este $2 echo Al 10-lea parametru pozitional este ${10}

Apelat astfel:
$./test 1 2 3 4 5 6 7 8 9 10 11

vom obine listing-ul:


Numele script-ului este ./test Primul parametru pozitional este 1 Al doilea parametru pozitional este 2 Al 10-lea parametru pozitional este 10

Comanda set poate fi folosit pentru resetarea parametrilor poziionali. Dac este apelat fr nici un argument, comanda set va afia toate variabilele care au fost definite n acel shell, locale sau exportate. n momentul apelului comenzii cu unul sau mai multe argumente, parametrii pozitionali definii anterior se pierd (pentru a reveni la valorile iniiale se poate utiliza comanda set --).

UNIX

Fie exemplul urmtor:


#!/bin/bash #Numele script-ului este test2 echo Numele script-ului este $0 echo Parametrii sunt: $* echo Al doilea parametru pozitional este $2 echo Numarul parametrilor este $# arg_vechi=$* set ion maria cornel gheorghe stefan echo Parametrii sunt acum: $* set $(date) echo Astazi este $3 $2 $6 echo Vechii parametri sunt: $arg_vechi set $arg_vechi echo $1 $2 $3

n urma execuiei shell-script-ului de mai sus prin apelul: ./test2 1 2 3 se va afia:


Numele script-ului este ./test2 Parametrii sunt: 1 2 3 Al doilea parametru pozitional este 2 Numarul parametrilor este 3 Parametrii sunt acum: ion maria cornel gheorghe stefan Astazi este 15 Aug 2004 Vechii parametri sunt: 1 2 3 1 2 3

Variabilele speciale pot fi folosite i n construcii speciale:


#!/bin/bash #Numele script-ului este test3 nume=${1:?necesita un argument!} echo Buna ziua, $1!

Dac test3 este apelat fr nici un argument, va fi afiat mesajul de eroare: ./test3: 1: necesita un argument! Dac facem apelul: ./test3 Razvan, vom obine rezultatul: Buna ziua, Razvan!

Bourne again shell

8.3.4 Construcii condiionale i controlul fluxului Construciile condiionale ne permit s testm anumite condiii i apoi s executm anumite comenzi n funcie de rezultatul testrilor. Comanda if reprezint cea mai simpl construcie condiional utilizat pentru luarea deciziilor. Ca i shell-ul Bourne, bash utilizeaz valoarea lui exit-status pentru a vedea care este rezultatul unei comenzi (reamintim c n cazul n care comanda s-a ncheiat cu succes sau cu valoarea logic true exit-status-ul este egal cu zero iar n caz contrar exit-status-ul are o valoare diferit de zero). Valoarea lui exit-status pentru ultima comand este $?. Pentru a evalua starea de adevr a unei expresii este folosit comanda intern test, sau se folosesc parantezele ptrate. Considerm n continuare cteva exemple de utilizare a comenzii test, a parantezelor ptrate, construcia cu paranteze ptrate duble [[ ]] i cu paranteze duble (( )). Exemplul 1.
Vom introduce la linia de comanda: $ nume=barbu $ grep $nume /etc/passwd > /dev/null $ echo $? 0 #barbu a fost gasit in /etc/passwd $ test $nume != barbu $ echo $? 1 #numele nu este diferit de barbu $ [ $nume = barbu ] $ echo $? 0 #testul este adevarat de aceasta data $ [ $nume = [Bb]arbu ] $ echo $? 1 #comanda test nu permite folosirea metacaracterelor

Pentru a putea utiliza metacaractere n cadrul comenzii test trebuie s folosim parantezele ptrate duble, ca n exemplul urmtor:
$ [[ $nume == [Bb]arbu ]] $ echo $? 0

UNIX

Prin utilizarea parantezelor duble (( )) se pot evalua expresii numerice. Considerm exemplul urmtor:
$ x=3; y=5 $ (( x > y )) $ echo $? 1

Rezultatul afiat este 1 deoarece x nu este mai mare dect y (3<5). Comanda if Noul format al comenzii if pentru bash este:
if [[ com_test1 ]] then secventa_comenzi1 else secventa_comenzi2 fi

sau, pentru testri numerice:


if (( com_test1 )) then secventa_comenzi1 else secventa_comenzi2 fi

Observaie. else este opional. Comanda exit Comanda exit este utilizat pentru a termina shell-script-ul i a reveni la linia de comand. Comenzii exit i se poate da un argument (un numr ntre 0 i 255) pentru a indica faptul c programul s-a ncheiat cu succes sau nu. Asemntor cu exit-status-ul, valoarea 0 nseamn ncheierea cu succes a programului. Argumentul pe care l dm comenzii exit se afl stocat n variabila $?.

Bourne again shell

Comanda case Comanda case este utilizat pentru construcii condiionale multiple. Formatul acesteia este acelai cu formatul shell-ului standard Bourne:
case variabila in sablon_1) comenzi ;; sablon_2) comenzi ;; *) comenzi ;; esac

Dac nici una dintre valorile sablon_1, sablon_2, etc. nu corespund valorii variabilei respective, se vor executa n mod implicit comenzile ce urmeaz dup construcia special *).

8.3.5 Comenzi de ciclare Comenzile utilizate pentru ciclare sunt: for, while, until, select. Dintre acestea, primele trei ne sunt familiare din shell-ul Bourne. n shell-ul bash apare un nou mecanism de ciclare, denumit select, utilizat cu principalul scop de a crea meniuri. Comanda select afieaz un meniu cu opiuni numerotate 1, 2, 3 etc. Afiarea se face n fiierul standard error (pe ecran, implicit). Pe ecran, cererea de a introduce una dintre opiuni se face prin afiarea prompter-ului PS3 (al treilea prompter), care implicit are valoarea #?. Dac dorim s afim un mesaj, va trebui s modificm doar valoarea lui PS3. Dar s vedem cum funcioneaz comanda select: dup afiarea meniului i a prompter-ului PS3, se ateapt pentru introducerea unui numr din lista afiat. Input-ul va fi stocat n variabila special REPLY. De regul, comanda select se folosete mpreun cu comanda case pentru a crea un meniu ce permite utilizatorului s fac o selecie dintr-un meniu i pe baza acelei selecii s execute anumite comenzi. De asemenea, se pot utiliza variabilele predefinite LINES i COLUMNS pentru a schimba modul de afiare pe ecran a opiunilor (aceste variabile sunt definite

UNIX

ncepnd cu versiunea 2.0 bash). Pentru a ntrerupe execuia comenzii select se va folosi fie break (pentru ieirea din ciclul select), fie exit pentru a iei din program. Formatul general al instruciunii select este:
select variabila in lista do comenzi done

Prezentm n continuare cteva exemple de utilizare a comenzii select. Exemplul 1.


#!/bin/bash # Nume shell-script: meniu_select PS3=Selectati optiunea dorita: select prog in uname -n date cal who exit do $prog done

Execuia programului va duce la afiarea unui meniu:


1) uname -n 2) date 3) cal 4) who 5) exit Selectati optiunea dorita:

n funcie de opiunea selectat, se va executa comanda respectiv. Ciclul select va rula fie pn la introducerea opiunii 5 (exit va determina ieirea din program), fie pn la introducerea combinaiei Ctrl+C.

Bourne again shell

Exemplul 2.
#!/bin/bash # Nume shell-script: culori PS3=Alegeti una dintre culori sau exit: select alegere in albastru galben verde exit do case alegere in albastru) echo Albastrul este culoarea cerului! break;; galben) echo Galbenul este o culoare calda! break;; verde) echo Verde este padurea! break;; *) echo $REPLY nu este o optiune valida! echo Incercati din nou. ;; esac done

Iniial, se va afia meniul:


1) albastru 2) galben 3) verde 4) exit Alegeti una dintre culori sau exit:

n funcie de opiunea aleas se va afia mesajul corespunztor. Dac se introduce valoarea 4 se va iei din program i orice alt valoare introdus va afia mesajul n care se precizeaz c nu este o opiune valid i se va repeta introducerea opiunii. Rularea instruciunilor de ciclare n background Instruciunile de ciclare pot fi rulate n background, astfel nct programul poate continua fr s atepte terminarea instruciunii de ciclare.

UNIX

n exemplul urmtor se trimite un email mai multor utilizatori preluat din fiierul scrisoare:
#!/bin/bash for nume in radu andrei andra serban gabi do mail $nume < scrisoare done &

Semnul & (ampersand) de la sfritul instruciunii for determin execuia ciclului for n background. Programul i va continua execuia pn la terminarea ciclului for. Separatorul IFS Separatorul intern al shell-ului IFS (Internal Field Separator) are valoare de spaiu, tab sau caracter de linie nou (newline). El este folosit drept caracter separator n cadrul comenzilor pentru interpretarea semantic a cuvintelor cheie, precum: for, do, done, etc. Acest separator poate fi modificat de ctre utilizator dac se dorete utilizarea altui separator ntr-o list. nainte de a modifica valoarea separatorului, este bine s memorm vechea valoare a lui IFS n alt variabil, pentru a putea reface starea iniial a separatorului. Prezentm n continuare un exemplu de modificare a separatorului IFS.
#!/bin/bash # Exemplu pentru IFS nume=Radu:Andrei:Andra:Serban:Gabi ifs_vechi=$IFS IFS=: for persoana in $nume do echo Salut $persoana done IFS=$ifs_vechi set Cristi Cristina Paul for prenume in $* do echo Buna ziua $prenume done

Bourne again shell

La nceput, variabila nume are valoarea irului de caractere Radu:Andrei:Andra:Serban:Gabi, numele fiind separate de cte un caracter :. Vechea valoare a lui IFS este memorat n variabila ifs_vechi. Deoarece valoarea lui IFS este un caracter whitespace, trebuie ncadrat ntre ghilimele. Apoi lui IFS i se atribuie o nou valoare, semnul : care va fi de acum utilizat pe post de separator. Ca urmare a execuiei shell-script-ului anterior se va afia:
Salut Radu Salut Andrei Salut Andra Salut Serban Salut Gabi Buna ziua Cristi Buna ziua Cristina Buna ziua Paul

8.3.6 Funcii Funciile au fost introduse n shell-ul Bourne ncepnd cu versiunea AT&T UNIX SystemVR2 (SVR2) i le-au fost adugate o serie de mbuntiri n shell-ul Bourne Again. Funciile reprezint asocierea unui nume pentru o comand sau un grup de comenzi, fiind folosite pentru modularizarea programelor, fcndu-le astfel mai eficiente. Funciile sunt executate n contextul shell-ului curent, astfel c nu se creeaz un nou proces copil ca n cazul rulrii unui program executabil precum cat. Funciile pot fi scrise n fiiere separate pentru a fi ncrcate n memorie din shell-script atunci cnd trebuie folosite. n continuare sunt prezentate regulile de scriere a funciilor n Bourne Again Shell: 1. O funcie trebuie definit nainte de a fi utilizat. 2. Funcia ruleaz n mediul de lucru curent, partajnd variabilele din shell-script-ul ce o invoc i ofer posibilitatea de transmitere de argumente prin atribuirea acestora ca parametri poziionali. Variabilele locale pot fi create n cadrul unei funcii prin utilizarea funciei local. 3. Shell-ul determin dac se folosete un alias, o funcie, o comand intern sau un program executabil aflat pe hard-disc. Ordinea de cutare este: alias, funcie, comand intern, program executabil. 4. n momentul n care se utilizeaz comanda exit n cadrul unei funcii, se produce ieirea din shell-script-ul ce apeleaz funcia. Dac se

UNIX

iese din funcie, ntoarcerea n shell-script se face pe linia urmtoare apelului funciei. 5. Comanda return n cadrul unei funcii determin returnarea valorii exit-status a ultimei comenzi executate n cadrul funciei sau valoarea argumentului specificat. 6. Funciile pot fi exportate n sub-shell-uri folosind comanda intern export -f. 7. Pentru a lista funciile i definiiile acestora, se folosete comanda declare -f. ncepnd cu versiunea 2.x. bash, pentru a lista doar numele funciilor se folosete comanda declare -F. 8. Dac funciile sunt stocate ntr-un fiier separat, acestea pot fi ncrcate n mediul curent prin comanda source sau comanda dot (.). 9. Se permite declarea funciilor recursive (ce se auto-apeleaz). Nu exist o limit maxim impus pentru numrul de apeluri recursive. 10. Variabilele, ca i valorile trap sunt globale n cadrul funciilor. Ele sunt partajate att de ctre shell-script ct i de funciile invocate de acel shell-script. Dac o valoare trap este definit n cadrul unei funcii, ea este, de asemenea, partajat de shell-script. Alte comenzi legate de funcii. Pentru a reseta o funcie se folosete comanda unset. Formatul general al acestei comenzi este:
unset -f nume_functie

Pentru a exporta o funcie ntr-un sub-shell se folosete comanda export. Formatul general al acestei comenzi este:
export -f nume_functie

n cadrul unei funcii, argumentele pot fi transmise funciilor prin intermediul parametrilor poziionali. Parametrii poziionali sunt privai n cadrul funciilor, astfel nct argumentele unei funcii nu vor afecta parametrii poziionali utilizai n afara acesteia. Pentru a crea variabile locale (care nu vor mai fi valabile la ieirea din funcie) pentru o funcie anume putem folosi comanda intern local. Comanda return poate fi utilizat pentru a termina execuia funciei i a preda controlul script-ului apelant. Valoarea returnat de o funcie este egal cu valoarea exit-status returnat de ultima comand executat

Bourne again shell

n cadrul funciei, cu excepia cazului n care se specific un anumit argument prin intermediul comenzii return. n momentul n care se specific o valoare prin comanda return, aceast valoare este stocat n variabila ? i poate lua valori ntregi cuprinse ntre 0 i 255. Datorit acestei limitri, se poate utiliza substituirea comenzii pentru a captura valoarea returnat de o funcie. n acest sens, se poate scrie toat funcia ntre paranteze precedate de semnul $ sau ntre apostrofurile inverse (``) pentru a captura i atribui valoarea returnat de ctre funcie unei variabile, ca i n cazul obinerii rezultatului unei comenzi UNIX. Prezentm n continuare cteva exemple de utilizare a funciilor. Exemplul 1.
#!/bin/bash # Nume shell-script: verific_functie function UTI { echo Eroare: $* 2>&1; exit 1; } if (( $# != 2 )) then UTI $0: necesita doua argumente fi if [[ ! ( -r $1 && -w $1 ) ]] then UTI $1: fara drepturi de citire si scriere fi echo Argumentele sunt: $* ...# comenzi

Explicaii. n exemplul anterior se definete o funcie UTI ce este utilizat pentru a afia un mesaj de eroare pe ecran (fiierul standard de eroare). Argumentele funciei constau n orice ir de caractere trimise odat cu apelul funciei. Argumentele sunt stocate n $*, variabila special ce stocheaz toi parametrii poziionali. n cadrul unei funcii, parametrii poziionali sunt considerai locali i nu au efect asupra parametrilor utilizai n afara funciei. n cadrul script-ului se verific dac numrul parametrilor poziionali este 2 i n caz contrar se afieaz mesajul de eroare corespunztor. n momentul apelrii funciei UTI, irul $0: necesita doua argumente este transmis funciei i memorat n variabila $* iar comanda echo va afia mesajul de eroare i apoi se va returna valoarea de ieire 1, ceea ce indic faptul c ceva nu a fost n regul. n continuarea programului,

UNIX

se verific dac primul argument este un fiier care poate fi citit i modificat, iar funcia UTI va fi apelat cu argumentul $1: fara drepturi de citire si scriere. Argumentele ce provin de la linia de comand sunt stocate din nou n $*, fr a avea efect pentru valoarea $* din cadrul funciei. Exemplul 2.
#!/bin/bash # Nume shell-script: incrementare INC () { local suma; let suma=$1 + 1 return $suma } echo -n Suma este: INC 5 echo $? echo $suma # variabila suma nu este cunoscuta in #afara functiei

Explicaii. n exemplul anterior se definete o funcie INC. n cadrul acestei funcii se declar variabila local suma, care nu este cunoscut n afara funciei. n momentul apelului funciei, valoarea primului argument, $1 va fi incrementat cu 1 iar rezultatul va fi atribuit variabilei suma. Comanda intern return va atribui variabilei $? valoarea din variabila suma, apoi irul este afiat pe ecran. Funcia INC este apelat cu argumentul 5, iar exit-status-ul ei va fi stocat n variabila $?. Pentru ultima linie din program nu se va afia nimic, deoarece variabila suma a fost declarat doar n interiorul funciei (cu ajutorul comenzii interne local) i valoarea acestei variabile nu este cunoscut n afara funciei.

Bourne again shell

Exemplul 3.
#!/bin/bash # Nume shell-script: cub function CUB { local rez; let rez=$1 * $1 * $1 echo Numarul ce va fi ridicat la cub este $1 echo Rezultatul este $rez } echo -n Introduceti numarul pentru ridicare la cub: read numar rezultat=$(CUB $numar) echo -n $rezultat

Explicaii. n exemplul anterior se definete o funcie CUB. n cadrul acestei funcii se declar variabila local rez, care va stoca rezultatul. n cadrul script-ului se citete valoarea care va fi ridicat la cub n variabila numar, apoi se atribuie variabilei rezultat valoarea ntoars de funcie prin intermediul substituirii comenzii (construcia cu numele funciei ntre paranteze precedate de semnul $). Prin comanda echo de pe ultima linie a shell-script-ului se afieaz rezultatul. Observaie. Ca i n Bourne Shell, funciile se ncarc n memorie cu ajutorul comenzii dot (.). n Bourne Again Shell exist ns i comanda source, care se apeleaz astfel:
$ source fisier_functii

unde fisier_functii este fiierul ce conine funciile ce vor fi utilizate.