Sunteți pe pagina 1din 8

Elemente suplimentare de programare SHELL

I. Comenzi de control a joburilor si proceselor. Coduri de ieire


Comanda jobs
Listeaz task-urile care ruleaz in background mpreuna cu identificatorii
acestora. Identificatorii joburilor sunt gestionai intern de ctre SHELL. Pentru
terminarea unui job se poate folosi fie kill %IDJOB fie kill PID.
Comenzile fg, bg
Comanda fg trece un anumit job in plan principal. Comanda bg trece jobul
respectiv in background. Daca nu este furnizat un job ca parametru, comenzile
acioneaz asupra celui mai recent job lansat.
Comanda wait
Oprete scriptul curent sa ruleze pana cnd un job (dat ca parametru) sau toate
joburile din background isi termina execuia. Comanda primete ca parametru un
identificator de job (ex. %1) sau PID-ul unui proces.
Comanda kill
Termina execuia unui proces trimindu-i un semnal SIGTERM sau un alt
semnal dat ca parametru. kill -l furnizeaz lista semnalelor disponibile in sistem.
Pentru a fi sigur de terminarea unui proces in cazul in care acesta nu rspunde la
SIGTERM, i se trimite un semnal SIGKILL : kill -9.
Coduri de iesire
Terminarea unui script se realizeaz prin comanda exit iar in cazul
funciilor se folosete cuvntul cheie return. In ambele cazuri se poate returna si
o valoare care este disponibila scriptului sau funciei apelante prin intermediul
variabilei $?. In absenta comenzilor exit/return, funciile si scripturile returneaz
un cod de ieire determinat de execuia ultimei comenzi.
II. Manipularea irurilor de caractere
BASH suporta un numr mare de operaii de manipulare a irurilor de
caractere. Unele dintre acestea rezulta din substituia parametrilor, altele deriva
din funcionalitatea comenzii expr.
Lungimea unui sir de caractere se poate obtine cu una dintre constructiile:
${#string} ; expr length $string sau expr "$string" : '.*'

Lungimea potrivirii unui subsir la nceputul unui sir de caractere se obine:


expr match "$string" '$substring' sau expr "$string" : '$substring'
stringZ=abcABC123ABCabc
echo `expr match "$stringZ" 'abc[A-Z]*.2'` # 8
echo `expr "$stringZ" : 'abc[A-Z]*.2'`
#8
Poziia primului caracter din irul $substring care se regsete in irul $string.
expr index $string $substring
stringZ=abcABC123ABCabc
echo `expr index "$stringZ" C12`
echo `expr index "$stringZ" 1c`

# 6 - pozitia C.
# 3 - 'c' se potriveste inaintea lui '1'.

Extragerea unui subsir de caractere


${string:position} - extrage subsirul din $string de la poziia $position. Daca
parametrul $string este "*" sau "@", se vor extrage parametrii poziionali
ncepnd cu poziia $position (irul ncepe de la poziia 0).
${string:position:length} extrage un numr de $length caractere din irul $string
ncepnd cu poziia $position. Parcurgerea se poate face si de la dreapta ctre
stnga folosind indeci negativi:
stringZ=abcABC123ABCabc
echo ${stringZ:(-4)}

# Cabc

expr substr $string $position $length extrage $length caractere din irul $string
ncepnd cu poziia $position.
expr "$string" : '\($substring\)' - extrage $substring la nceputul lui $string, unde
$substring este o expresie regulata.
stringZ=abcABC123ABCabc
echo `expr match "$stringZ" '\(.[b-c]*[A-Z]..[0-9]\)'` # abcABC1
echo `expr "$stringZ" : '\(.......\)'`
# abcABC1
expr match "$string" '.*\($substring\)' - extrage $substring la sfritul lui $string.
stringZ=abcABC123ABCabc
echo `expr match "$stringZ" '.*\([A-C][A-C][A-C][a-c]*\)'` # ABCabc
echo `expr "$stringZ" : '.*\(......\)'`
# ABCabc
Stergerea subsirurilor de caractere
${string#substring} nltura cea mai scurta potrivire a irului $substring de la
nceputul lui $string.

${string##substring} nltura cea mai lunga potrivire a irului $substring de la


nceputul lui $string.
stringZ=abcABC123ABCabc
echo ${stringZ#a*C} # 123ABCabc - cea mai scurta potrivire abcABC
echo ${stringZ##a*C} # abc cea mai lunga potrivire abcABC123ABC
${string%substring} nltura cea mai scurta potrivire a subsirului $substring de la
sfritul irului $string.
${string%%substring}- nltura cea mai lunga potrivire a subsirului $substring de
la sfritul irului $string.
Inlocuirea sirurilor de caractere
${string/substring/replacement} nlocuiete prima potrivire a
$substring cu $replacement.
${string//substring/replacement} nlocuiete toate potrivirile
$substring cu $replacement.

subsirului
subsirului

stringZ=abcABC123ABCabc
echo ${stringZ/abc/xyz} # xyzABC123ABCabc
echo ${stringZ//abc/xyz} # xyzABC123ABCxyz
${string/#substring/replacement} daca $substring se potrivete la nceputul lui
$string, el se nlocuiete cu $replacement.
${string/%substring/replacement} - daca $substring se potrivete la sfritul lui
$string, el se nlocuiete cu $replacement.
III. Variabile. Declarare. Tipuri. Constante. Substitutia parametrilor
Comenzile interne declare sau typeset permit restricionarea proprietilor unei
variabile. Opiunile cele mai frecvente sunt :
-r readonly
-i integer trateaz apariiile ulterioare ale variabilei ca un numr ntreg.
-a array declararea unei variabile ca un vector.
-f functions afiarea corpului unei funcii
-x - declararea unei variabile spre a fi exportata in afara scriptului ctre
scripturile pe care acesta le apeleaz. Variabila nu poate fi insa exportata ctre
scriptul printe! Are acelai efect ca si comanda export. O ntrebuinare frecventa
o are comanda export in fiierele iniiale de configurare pentru a exporta
variabilele de mediu ctre procesele ce urmeaz sa fie lansate.

Comanda read
Opiunea -a permite citirea mai multor valori intr-o variabila de tip array. Pentru
scrierea pe mai multe linii, se folosete simbolul \. Pentru citirea acestui simbol
literal, el trebuie escapat prin folosirea construciei \\. Alte opiuni interesante:
read -s -n6 -p "Introduceti 6 caractere > " keypress
echo; echo "Keypress was "\"$keypress\""."
# -s nu arata caracterele ce au fost introduse
# -n N citeste numai N caractere
# -p afisarea unui prompter inaintea introducerii datelor
Referirea indirecta a unei variabile
Sa presupunem ca valoarea unei variabile este numele unei alte variabile. Cum e
posibil sa regsim valoarea celei de-a doua variabile plecnd de la prima ? De
exemplu, daca x=y si y=1, referina indirecta se poate realiza prin folosirea
comenzii eval v=\$$x .
In general, comanda eval args concateneaz si evalueaz mai nti valoarea
argumentelor dup care executa comanda rezultata. Prin urmare, expresia de mai
sus se descompune in doi pai : evaluarea (v=$y) si apoi execuia comenzii de
atribuire. Referirea indirecta a variabilelor ofer BASH-ului puin din
funcionalitatea pointerilor din limbajul C. Versiunea 2 a BASH-ului permite
referirea indirecta prin ${!variable}.
for i in ls df; do
value=eval $i ; echo $value
done
Generarea numerelor aleatoare
$RANDOM este o funcie interna a Bash-ului ce returneaz un ntreg pseudoaleator in intervalul 0 - 32767. Resetarea generatorului de numere pseudoaleatoare se face prin intermediul variabilei RANDOM. Exemplu: RANDOM=$$
(identificatorul de proces al SHELL-ului).
Comanda let si constructia (( ... ))
Ambele permit evaluarea expresiilor aritmetice intr-un mod similar limbajului C.
let x=2; let x++ ; ((--x)); ((y=x==2?1:0)) ; echo $y
Constante numerice
Shell-ul BASH interpreteaz numerele implicit in baza 10, daca acestea nu
conin prefixe speciale. Astfel, numerele in baza 8 sunt prefixate cu simbolul 0

iar cele in baza 16 cu simbolul 0X. In general, reprezentarea unui numr intr-o
baza oarecare (cuprinsa intre 2 si 64) se realizeaz prin construcia :
BASE#NUMBER.
let x=2#101 ; let y=032 ; let z=0X11; echo $x $y $z
Substitutia parametrilor
${parameter-default} daca parametrul nu este setat, ia valoarea default.
echo ${username-`whoami`}
# afiseaza rezultatul comenzii whoami, daca variabila $username nu e setata.
Construcia default parameter isi gsete ntrebuinarea in scripturi atunci cnd
sunt omii anumii parametri in linia de comanda.
${parameter=default} daca parametrul nu este setat, il seteaz la valoarea default
${parameter+alt_value} daca parametrul este setat, folosete valoarea alt_value,
altfel folosete irul NULL.
${parameter?err_msg} daca parametrul este setat atunci se folosete valoarea sa,
daca nu se afieaz mesajul de eroare.
IV. Comenzi interne
O comanda interna (builtin) este o comanda coninuta in setul intern de comenzi
al BASH-ului. Acestea sunt concepute fie din motive de performanta (builtinurile se executa mai rapid dect comenzile externe) sau datorita faptului ca o
comanda interna necesita accesul direct la mediul SHELL-ului.
O comanda externa se executa prin lansarea unui nou proces utiliznd
mecanismul de creare a proceselor : fork-exec. O comanda externa poate fi
sinonima cu o comanda interna cu acelai nume, pe care BASH-ul o
implementeaz intern. De exemplu comanda interna echo este diferita de
comanda externa /bin/echo.
#!/bin/bash
PIDS=$(pidof sh $0) # ID-urile instantelor scriptului curent
P_array=( $PIDS ) # preluarea lor intr-un sir de caractere
echo $PIDS
let "instances = ${#P_array[*]} - 1" # numararea instantelor
echo "$instances instance(s) of this script running."
echo "[Hit Ctl-C to exit.]"; echo
sleep 1
sh $0
# lanseaza din nou scriptul
exit 0
# ajunge programul sa execute acest exit 0 ?

Comenzile set, unset


Comanda set schimba valoarea variabilelor interne ale unui script. O aplicaie ar
fi testarea scriptului in funcie de ali parametri de intrare; o alta aplicaie este
preluarea parametrilor poziionali din ieirea altei comenzi set `command`.
Invocarea sa simpla permite afiarea tuturor variabilelor de mediu iniializate.
set `uname -a` # Seteaza parametrii poziionali in funcie de ieirea `uname -a`
Comanda unset terge o variabila SHELL, fara sa afecteze parametrii pozitionali.
unset PATH; echo $PATH
Comanda getopts
Aceasta unealta parseaza argumentele unui script din linia de comanda Ea
permite scrierea si concatenarea mai multor opiuni si a argumentelor asociate
unui script. (exemplu scriptname -abc -e /usr/local).
getopts folosete doua variabile implicite : $OPTIND este pointerul argument
(OPTion INDex) iar $OPTARG (OPTion ARGument) argumentul asociat care
poate fi opional ataat unei opiuni. getopts se folosete de obicei intr-o bucla
while, ce proceseaz opiunile si argumentele unul cate unul, apoi incrementeaz
variabila implicita $OPTIND pentru a trece a urmtorul pas. Argumentele trebuie
sa fie nsoite de simbolul -.
# a, b si c sunt optiunile asteptate; a si c sunt insotite de argumente
while getopts "a:bc: " option
do
case $option in
a ) # Executa taskurile asociate optiunii 'a' si a argumentului $OPTARG
b ) # Executa taskurile asociate optiunii 'b'
c ) # Executa taskurile asociate optiunii 'c' si a argumentului $OPTARG
esac
done
shift $(($OPTIND - 1))
Comanda source (.)
Aceasta comanda, atunci cnd este invocata din linia de comanda, executa un
script. In cadrul unui script, o comanda source file-name ncarc fiierul filename. Fcnd sourcing pe un fiier importam de fapt codul in cadrul scriptului
(acelai efect pe care il are directiva #include intr-un program C). Daca fiierul
dat ca parametru comenzii source este un script executabil, atunci codul acestuia
va fi executat, si apoi va ntoarce controlul scriptului apelant

Comanda exec
Aceasta comanda nlocuiete procesul curent incarcand si apoi executnd codul
aferent unei alte comenzi. In mod normal, la lansarea unei noi comenzi, se face
un apel fork() pentru crearea unui proces copil in cadrul cruia va fi executata
comanda. Cu exec, comanda data ca parametru nlocuiete codul Shell-ului.
Comanda type
Comanda similara cu comanda externa which, type ofer informaii despre
comanda trecuta ca parametru. Este utila folosirea opiunii -a pentru
identificarea cuvintelor cheie si a tuturor comenzilor cu nume identice.
V. Calcule in virgula mobila
Desi Shell-ul nu dispune de facilitai de lucru cu numere reale, se poate
folosi utilitarul bc pentru astfel de calcule. Acesta dispune chiar de un limbaj
redus de instruciuni si poate fi conectat prin pipe la o comanda pentru a executa
instruciunile trimise de aceasta.
De exemplu, pentru rezolvarea ecuaiei de gradul II, se va scrie un
program folosind limbajul propriu bc, iar din cadrul unui script se vor transmite
catre bc valori pentru cei trei coeficienti ca in exemplul de mai jos.
echo -n "" > temp.out
echo "a=$1;" >> temp.out
echo "b=$2;" >> temp.out
echo "c=$3;" >> temp.out
cat prog.out >> temp.out
cat temp.out | bc -l -q
fisierul prog.out contine codul sursa pentru rezolvarea ecuatiei de gradul II in limbaj bc
/*a=1; b=-3; c=2;*/
delta=b*b-4*a*c;
if(delta<0)
{
print "Nu sunt solutii reale\n";
}
if(delta>=0)
{
x1=(-b+sqrt(delta))/2*a;
x2=(-b-sqrt(delta))/2*a;
print "x1=";x1; print "x2=";x2
}

VI. Exerciii
1) Sa se elaboreze un script care sa listeze recursiv coninutul unui director si sa
salveze aceste informaii intr-un fiier. Fiierul va fi comprimat cu ajutorul
utilitarului tar, iar utilizatorului i se va cere sa introduc un stick USB. Cnd
acesta confirma conectarea stickului, fiierul va trebui salvat pe stick.
2) Sa se scrie un script care sa citeasc linie cu linie un fiier si apoi sa-l afieze la
ieirea standard insernd cate o linie goala intre liniile sale. Se va verifica de
asemenea daca fiierul dat ca parametru exista. Sa se scrie apoi un script care
transforma un fiier dublu spaiat intr-un fiier simplu eliminnd liniile vide.
3) Sa se scrie un script care se afieaz pe el nsui la ieirea standard dar fiecare
linie va fi scrisa in ordine inversa.
4) Data fiind o lista de fiiere arhivate ca parametri de intrare, sa se scrie un
script care sa detecteze tipul fiecrui fiier (comanda file!) pentru a depista tipul
arhivei. In funcie de acest tip, scriptul va apela utilitarul corespunztor (gunzip,
bunzip2, unzip, uncompress) pentru a decompresa fiierele.
5) Sa se genereze un ID unic de 6 cifre pentru identificarea staiei de lucru, fara a
folosi comanda hostid. Pentru aceasta se va folosi utilitarul md5sum si se va face
un rezumat al fiierului /etc/passwd, apoi se vor selecta primele 6 cifre.
6) Sa se scrie un script care sa afieze toate numerele prime intre doua numere
ntregi primite ca parametri.
7) Sa se genereze 6 numere aleatoare distincte intre 1 si 49. Scriptul va oferi
opiunea de a afia numerele la ieirea standard sau intr-un fiier, mpreuna cu
data si ora la care setul a fost generat.
8) Sa se scrie o funcie care determina daca argumentul sau este un ntreg sau un
sir de caractere ordinar. Funcia va ntoarce 0 daca argumentul este ntreg si 1
altfel. Folosii comanda expr si verificai codul sau de ieire.
9) Sa se listeze toate fiierele din directorul /home/student care depesc 1MB.
Pentru fiecare fiier, utilizatorul va avea posibilitatea de a alege sa tearg fiierul
sau sa-l comprime. Numele fiierelor terse vor fi scrise intr-un jurnal.
10) Sa se afieze informaiile (din fiierul /etc/passwd) referitoare la utilizatorii
care nu si-au mai accesat conturile in ultimele 90 zile. Scriei o funcie care sa
permit compararea a doua date calendaristice.