0% au considerat acest document util (0 voturi)
33 vizualizări22 pagini

Shell Scripting

Shell scripting este o metodă de automatizare a sarcinilor prin crearea de scripturi care rulează în shell-uri Unix, cum ar fi bash. Acesta permite gestionarea fișierelor, execuția de comenzi în loturi și interacțiunea cu utilizatorul. Scripturile pot include variabile, array-uri, structuri de control if-then-else și pot efectua calcule matematice.

Încărcat de

addelyka
Drepturi de autor
© © All Rights Reserved
Respectăm cu strictețe drepturile privind conținutul. Dacă suspectați că acesta este conținutul dumneavoastră, reclamați-l aici.
Formate disponibile
Descărcați ca TXT, PDF, TXT sau citiți online pe Scribd
0% au considerat acest document util (0 voturi)
33 vizualizări22 pagini

Shell Scripting

Shell scripting este o metodă de automatizare a sarcinilor prin crearea de scripturi care rulează în shell-uri Unix, cum ar fi bash. Acesta permite gestionarea fișierelor, execuția de comenzi în loturi și interacțiunea cu utilizatorul. Scripturile pot include variabile, array-uri, structuri de control if-then-else și pot efectua calcule matematice.

Încărcat de

addelyka
Drepturi de autor
© © All Rights Reserved
Respectăm cu strictețe drepturile privind conținutul. Dacă suspectați că acesta este conținutul dumneavoastră, reclamați-l aici.
Formate disponibile
Descărcați ca TXT, PDF, TXT sau citiți online pe Scribd

Shell scripting

Shell scripting este o metodă prin care se creează programe sau scripturi ce sunt
executate într-un shell al sistemului de operare. Shell scripting-ul este puternic
și flexibil, permițând automatizarea sarcinilor repetitive, gestionarea sistemului,
executarea comenzi complexe și multe altele.

Scripturile shell sunt de obicei scrise pentru shell-uri de tip Unix, cum ar fi
Bourne Shell (sh), Bourne Again Shell (bash), C Shell (csh), Korn Shell (ksh), și
altele, fiecare având propria sa sintaxă și set de funcționalități. Cel mai comun
shell utilizat pentru scripting în sistemele Linux și Unix este bash.

Caracteristici principale ale Shell Scripting:


Automatizarea sarcinilor: Poți automatiza sarcinile de rutină cum ar fi backup-ul
de date, actualizările de sistem și gestionarea fișierelor.

Execuție de comenzi în loturi: Permite executarea unei serii de comenzi într-o


singură rulare, fără intervenție manuală.

Manipularea fișierelor și directoarelor: Poți crea, șterge, muta și modifica


fișiere și directoare.

Gestionarea proceselor: Permite oprirea, pornirea și monitorizarea proceselor de


sistem.

Interacțiune cu utilizatorul: Poți solicita input de la utilizator, afișa mesaje și


oferi feedback.

Exemplu simplu de Shell Script:


Copy
#!/bin/bash

# Afișează un mesaj de bun venit


echo "Bine ai venit!"

# Cere utilizatorului să introducă numele


echo -n "Te rog să îți introduci numele: "
read nume

# Salută utilizatorul
echo "Salut, $nume!"
Acest script utilizează:

#!/bin/bash pentru a specifica interpretorul care va executa scriptul.

echo pentru a afișa mesaje.

read pentru a citi intrarea de la tastatură.

Pentru a executa un script shell pe un sistem Unix sau Linux, trebuie să urmezi
câțiva pași simpli. Presupunând că ai un script salvat cu numele script.sh, iată
cum l-ai putea rula:

1. Fă Scriptul Executabil
În primul rând, trebuie să te asiguri că scriptul are permisiuni de executare.
Acest lucru se face cu comanda chmod (change mode). Deschide un terminal și
navighează la directorul unde ai salvat scriptul. Apoi, rulează:

Copy
~$ chmod +x script.sh
Această comandă modifică permisiunile fișierului script.sh pentru a permite
executarea acestuia.

2. Execută Scriptul
După ce ai acordat permisiunile necesare, există două moduri prin care poți executa
scriptul:

Opțiunea 1: Folosind Calea Relativă sau Absolută

Dacă te afli în același director cu scriptul, îl poți executa folosind o cale


relativă:

Copy
~$ ./script.sh
Dacă scriptul se află într-un alt director, poți utiliza calea absolută:

Copy
~$ /path/to/your/script.sh
Opțiunea 2: Folosind Interpretorul Direct

De asemenea, poți folosi shell-ul direct pentru a executa scriptul, fără a modifica
permisiunile de executare. Dacă scriptul este scris pentru Bash, folosești:

Copy
~$ bash script.sh
Acest mod de executare interpretează direct conținutul fișierului ca un script
Bash, fără a necesita permisiuni de executare pe fișier.

Note Importante
Asigură-te că prima linie a scriptului tău conține shebang-ul (#!) urmat de calea
către interpretorul adecvat. Pentru un script Bash, aceasta este de obicei
#!/bin/bash.

Dacă întâmpini erori referitoare la "bad interpreter: No such file or directory",


verifică shebang-ul pentru erori de cale.

Comentarii în Bash Script


Comentarii pe o singură linie: Încep cu simbolul #. Tot textul de pe linie după #
este tratat ca un comentariu.

Comentarii pe mai multe linii: Bash nu are o sintaxă specifică pentru comentariile
pe mai multe linii similar cu alte limbaje de programare, dar poți folosi mai multe
linii de comentarii pe o singură linie sau un hack folosind : '...comment...'.

Copy
#!/bin/bash

# Acest script afișează un mesaj de salut.

echo "Salut!"

# Calcularea sumei a două numere


numar1=5
numar2=10
suma=$((numar1 + numar2)) # Adună numărul1 și numărul2

echo "Suma este: $suma"

# Următoarele linii sunt comentate și nu vor fi executate


# echo "Acesta este un comentariu pe mai multe linii."
# echo "Această parte a codului este dezactivată pentru demonstrație."

# Folosind hack-ul pentru comentarii pe mai multe linii


: '
Acesta este un exemplu de comentariu
pe mai multe linii folosind hack-ul cu :
'
Utilizarea Variabilelor
În exemplul anterior, variabilele numar1 și numar2 sunt folosite pentru a stoca
valori numerice. Apoi, aceste valori sunt folosite pentru a efectua un calcul
matematic.

Copy
numar1=5
numar2=10
Alocarea valorilor variabilelor se face fără spații în jurul semnului =. Pentru a
accesa valoarea unei variabile, se utilizează semnul $ înaintea numelui variabilei.

Calculul Expresiei Matematice


Shell-ul Bash permite efectuarea calculului expresiilor matematice folosind diverse
metode. În exemplul dat, este folosită comanda internă $((expresie)) pentru a
evalua suma a două numere.

Copy
suma=$((numar1 + numar2)) # Adună numărul1 și numărul2
Acest mecanism, $((expresie)), evaluează expresia matematică specificată în
interiorul parantezelor duble și atribuie rezultatul variabilei suma. În acest caz,
numar1 și numar2 sunt adunate, iar rezultatul lor, 15, este stocat în variabila
suma.

Afișarea rezultatului se face folosind echo:

Copy
echo "Suma este: $suma"
Aceasta afișează valoarea variabilei suma în consolă, care în exemplul nostru este
15.

În Bash scripting, variabilele nu sunt tipizate în mod strict în sensul limbajelor


de programare static tipizate precum Java sau C++. În schimb, Bash tratează toate
variabilele ca șiruri de caractere (strings). Cu toate acestea, Bash permite
efectuarea de operații aritmetice pe variabile fără a necesita conversia explicită
între tipuri de date, atâta timp cât valorile variabilelor pot fi interpretate ca
numere.

Caracteristici ale Variabilelor în Bash:


Dinamice: Variabilele în Bash pot stoca atât numere cât și text, și tipul lor poate
fi schimbat dinamic în timpul execuției scriptului.

Conversia Automată: Când efectuați operații aritmetice, Bash încearcă să


convertească automat valorile la numere. Dacă o variabilă conține un șir care poate
fi interpretat ca un număr, atunci poate fi utilizat direct în expresii aritmetice.

Lipsa Declarației: Nu este necesar să declari tipul unei variabile înainte de a o


folosi. Atribuirea unei valori unei variabile este suficientă pentru a o declara.

Chiar dacă Bash gestionează variabilele într-un mod flexibil, această flexibilitate
vine cu responsabilitatea de a asigura că valorile variabilelor sunt adecvate
pentru operațiile la care sunt supuse. De exemplu, încercarea de a efectua o
operație aritmetică cu un șir de caractere care nu poate fi interpretat ca un număr
va duce la o eroare.

Array-uri (Vectori)
Array-urile permit stocarea mai multor valori într-o singură variabilă, fiecare
valoare putând fi accesată printr-un index. Bash suportă array-uri unidimensionale.

Exemplu de Declarare și Utilizare:

Copy
nume=('Alice' 'Bob' 'Carol')
echo "${nume[0]}" # Afișează Alice
echo "${nume[@]}" # Afișează toate elementele array-ului
echo "${#nume[@]}" # Afișează numărul de elemente din array

nume+=("Dave")
echo "${nume[@]}" # Afișează toate elementele array-ului, inclusiv Dave
Lucrul cu sub-array-uri (sau porțiuni dintr-un array) se poate face utilizând
sintaxa de slicing de array-uri. Aceasta permite extragerea unei secțiuni dintr-un
array bazată pe indicii de start și stop. Sintaxa generală pentru slicing este:

Copy
${array[@]:pozitie_start:lungime}
Unde:

array este numele array-ului din care vrei să extragi sub-array-ul.

pozitie_start este indicele elementului de la care începe extracția (indicele


începe de la 0).

lungime este numărul de elemente de extras din array, începând cu pozitie_start.

Exemplu de Utilizare
Să presupunem că avem următorul array:

Copy
numere=(0 1 2 3 4 5 6 7 8 9)
Dacă dorim să extragem un sub-array care începe de la indicele 3 și are lungimea 4,
vom folosi:

Copy
echo "${numere[@]:3:4}"
Acesta va afișa:

Copy
3 4 5 6
Dacă omiti parametrul lungime, se vor extrage toate elementele începând cu
pozitie_start până la sfârșitul array-ului.

Bash nu suportă direct array-uri multidimensionale, așa că lucrul cu sub-array-uri


necesită manipulare manuală sau abordări creative pentru structuri de date mai
complexe.

Array-uri Asociative (Dictionare sau Map-uri)


Array-urile asociative sunt o extensie a array-urilor simple și permit accesarea
valorilor folosind chei unice, în loc de indici numerici. Sunt similare cu
dictionarele din Python sau obiectele din JavaScript.

Exemplu de Declarare și Utilizare:


Pentru a folosi array-uri asociative, trebuie să declarăm variabila folosind
declare -A:

Copy
declare -A capitale
capitale["Franța"]="Paris"
capitale["Germania"]="Berlin"
echo "Capitala Franței este: ${capitale["Franța"]}"
IF / THEN / ELSE
Structura if-then-else în Bash este o construcție fundamentală folosită pentru a
testa condiții și a executa diferite blocuri de cod bazate pe rezultatul testului.
Această structură permite scripturilor să ia decizii și să execute diferite acțiuni
în funcție de diferite condiții.

Sintaxa de bază
Copy
if [ condiție ]; then
# Comenzi executate dacă condiția este adevărată
else
# Comenzi executate dacă condiția este falsă
fi
if - începe testul condițional.

[ condiție ] - condiția care trebuie evaluată. Parantezele drepte [ ] reprezintă


comanda test în Bash.

then - dacă condiția evaluată este adevărată, comenzile care urmează până la else
sau fi vor fi executate.

else - (opțional) specifică comenzile care vor fi executate dacă condiția este
falsă.

fi - încheie blocul if.

Exemplu 1: Test simplu


Copy
#!/bin/bash

numar=10

if [ $numar -eq 10 ]; then


echo "Numărul este egal cu 10."
else
echo "Numărul nu este egal cu 10."
fi
Acest script va afișa "Numărul este egal cu 10." pentru că condiția testată ($numar
-eq 10) este adevărată.

Exemplu 2: Verificarea Existentei unui Fișier


Copy
#!/bin/bash

filename="document.txt"

if [ -e "$filename" ]; then
echo "Fișierul există."
else
echo "Fișierul nu există."
fi
Acest script verifică dacă fișierul document.txt există în directorul curent. Dacă
fișierul există, va afișa "Fișierul există."; altfel, va afișa "Fișierul nu
există."

Exemplu 3: Structură If-Elif-Else


Bash permite și utilizarea elif pentru a testa condiții multiple în aceeași
structură if.

Copy
#!/bin/bash

nota=85

if [ $nota -ge 90 ]; then


echo "Ai obținut A."
elif [ $nota -ge 80 ]; then
echo "Ai obținut B."
else
echo "Ai obținut C sau mai jos."
fi
Acest script evaluează o notă și afișează calificativul corespunzător. În exemplul
nostru, va afișa "Ai obținut B.".

Este important să pui spațiu după [ și înainte de ] în condiția if.

Pentru a testa mai multe condiții în cadrul aceleiași instrucțiuni if, poți folosi
operatorii logici && (și) și || (sau).

Folosirea ghilimelelor în jurul variabilelor, de exemplu, "$filename", previne


erori legate de valori goale sau conținând spații.

În Bash, operatorii de test sunt folosiți pentru a evalua condiții în


instrucțiunile de control, cum ar fi if, while, și until. Acești operatori permit
compararea numerică, verificarea șirurilor de caractere, testarea atributelor
fișierelor și altele. Iată o listă a celor mai comuni operatori de test în Bash:

Testarea Numerică
-eq: egal cu (ex: $a -eq $b)

-ne: nu este egal cu (ex: $a -ne $b)

-gt: mai mare decât (ex: $a -gt $b)

-ge: mai mare sau egal cu (ex: $a -ge $b)

-lt: mai mic decât (ex: $a -lt $b)

-le: mai mic sau egal cu (ex: $a -le $b)

Testarea Șirurilor de Caractere


= sau ==: egal (ex: $a = $b)

!=: nu este egal (ex: $a != $b)

-z: șirul este gol (ex: -z $a)

-n: șirul nu este gol (ex: -n $a)


$a: șirul a are o lungime mai mare decât 0

Testarea Fișierelor
-e: fișierul există (ex: -e fisier.txt)

-f: fișierul există și este un fișier obișnuit (nu un director sau un dispozitiv)
(ex: -f fisier.txt)

-d: fișierul există și este un director (ex: -d director)

-r: fișierul există și este citibil (ex: -r fisier.txt)

-w: fișierul există și este scriibil (ex: -w fisier.txt)

-x: fișierul există și este executabil (ex: -x script.sh)

-s: fișierul există și nu este gol (are dimensiunea mai mare decât zero) (ex: -s
fisier.txt)

-L: fișierul există și este un link simbolic (ex: -L link_simbolic)

Operatori Logici
!: negație (inversarea stării de adevăr) (ex: ! -e fisier.txt)

-a sau &&: și logic (ex: [$a -lt 20] && [$b -gt 100])

-o sau ||: sau logic (ex: [$a -lt 20] || [$b -gt 100])

Pentru a utiliza acești operatori în scripturile tale Bash, poți folosi comanda
test sau paranteze pătrate (de exemplu, [ $a -lt $b ]). Este important să pui
spațiu după [, înainte de ], și în jurul operatorilor pentru a asigura
interpretarea corectă a expresiei de către shell.

Structuri repetitive: FOR / WHILE / UNTIL


Aceste structuri sunt esențiale pentru scrierea scripturilor care necesită
iterație, cum ar fi procesarea colecțiilor de date sau așteptarea schimbării unei
condiții.

1. FOR
Structura for repetă un set de comenzi pentru fiecare element dintr-o listă.

Exemplu:

Copy
#!/bin/bash

for nume in Alice Bob Carol


do
echo "Salut, $nume!"
done
Acest script va afișa un mesaj de salut pentru fiecare nume specificat în listă.

Structura for în Bash poate fi utilizată și cu un iterator numeric, permițând


iterarea printr-o secvență de numere. Acest lucru este des realizat folosind o
sintaxă specifică, care seamănă cu cea din limbajele de programare tradiționale.
Iată un exemplu care afișează numerele de la 1 la 5:

Exemplu 2:
Copy
#!/bin/bash

for (( i=1; i<=5; i++ ))


do
echo "Numărul curent este: $i"
done
Exemplu 3:
Copy
#!/bin/bash

#iterarea element cu element printr-un array, cu acces la indice


nume=('Alice' 'Bob' 'Carol')
for i in "${!nume[@]}"; do
echo "Salut, ${nume[i]}!"
done
Aici, ${!nume[@]} generează o listă de indici pentru array-ul nume, iar for
iterează prin acești indici. Variabila i reprezintă pe rând fiecare indice,
permițându-ți să accesezi elementul corespunzător din array (${nume[i]}).

2. WHILE
Structura while execută un bloc de comenzi atât timp cât o condiție este adevărată.

Exemplu:

Copy
#!/bin/bash

contor=1
while [ $contor -le 5 ]
do
echo "Iterația $contor"
((contor++))
done
Acest script va afișa numărul iterației de cinci ori, incrementând variabila contor
la fiecare pas până când aceasta devine mai mare decât 5.

3. UNTIL
Structura until este similară cu while, dar repetă comenzi până când condiția
devine adevărată (adică face loop pe condiție falsă).

Exemplu:

Copy
#!/bin/bash

contor=1
until [ $contor -gt 5 ]
do
echo "Iterația $contor"
((contor++))
done
Acest script funcționează la fel ca exemplul while, afișând numărul iterației până
când contor depășește 5. Diferența principală este în verificarea condiției: until
execută blocul de comenzi atât timp cât condiția este falsă.

Exemple comenzi in script


1. Căutarea unui Text în Fișiere
Acest script folosește grep pentru a căuta un șir specific în toate fișierele .txt
din directorul curent.
Copy
#!/bin/bash

search_string="error"
for file in *.txt; do
echo "Caută '$search_string' în $file:"
grep "$search_string" "$file" && echo "Găsit în $file" || echo "Nu a fost găsit
în $file"
done
2. Numărarea Fișierelor dintr-un Director
Scriptul folosește find pentru a număra toate fișierele dintr-un anumit director.

Copy
#!/bin/bash

directory="/var/log"
num_files=$(find "$directory" -type f | wc -l)
echo "Există $num_files fișiere în directorul $directory."
3. Backup al unui Director
Acest script creează un arhivă (backup) tar.gz a unui director specificat și îl
salvează într-un alt director.

Copy
#!/bin/bash

# Setează directorul sursă și locația de backup


director_sursa="/path/to/source_directory"
destinatie_backup="/path/to/backup_directory"
nume_arhiva="$(basename "$director_sursa")_$(date +%Y-%m-%d).tar.gz"

# Creează backup
tar -czf "$destinatie_backup/$nume_arhiva" "$director_sursa"

echo "Backup completat: $destinatie_backup/$nume_arhiva"


4. Verificarea Stării Serviciilor
Scriptul următor verifică starea unor servicii specifice pe un sistem Linux și
afișează dacă acestea sunt active sau nu.

Copy
#!/bin/bash

# Definește serviciile de verificat


servicii=("nginx" "mysql" "ssh")

for serviciu in "${servicii[@]}"; do


echo -n "Verifică starea serviciului $serviciu: "

if systemctl is-active --quiet "$serviciu"; then


echo "Activ"
else
echo "Inactiv"
fi
done
5. Curățarea Fișierelor Temporare
Scriptul de mai jos șterge fișierele temporare din directorul /tmp care au fost
modificate ultima dată acum mai mult de 10 zile. Este o metodă utilă pentru a
elibera spațiu pe disc.
Copy
#!/bin/bash

# Setează numărul de zile


zile=10

# Găsește și șterge fișierele


find /tmp -type f -mtime +$zile -exec rm {} \;

echo "Fișierele temporare mai vechi de $zile zile au fost șterse."


Reutilizarea codului
În Bash scripting, funcțiile sunt un mijloc excelent de a reutiliza codul, ceea ce
face scripturile mai organizate și mai ușor de întreținut. O funcție este un bloc
de comenzi care poate fi executat ori de câte ori este nevoie. Prin definirea
funcțiilor, poți grupa comenzi frecvent utilizate sau complexe într-o singură
unitate reutilizabilă.

Definirea unei Funcții


Sintaxa de bază pentru definirea unei funcții în Bash este:

Copy
nume_functie() {
# comenzi
}
Sau

Copy
function nume_functie {
# comenzi
}
Exemplu: Funcție pentru Afisarea Salutului
Copy
#!/bin/bash

salut() {
echo "Salut, $1!"
}

# Apelarea funcției cu diferiți parametri


salut Alice
salut Bob
În acest exemplu, funcția salut primește un parametru ($1), care este folosit
pentru a personaliza mesajul afișat. Funcția este apoi apelată de două ori cu
argumente diferite, demonstrând reutilizarea codului.

Exemplu: Funcție pentru Calculul Sumelor


Copy
#!/bin/bash

suma() {
echo $(($1 + $2))
}

# Apelarea funcției și afișarea rezultatului


rezultat=$(suma 3 5)
echo "Suma este: $rezultat"
Acest script definește o funcție suma care primește doi parametri și afișează suma
lor. Funcția este apoi apelată, iar rezultatul este stocat în variabila rezultat și
afișat.
Funcția calculează suma 3 + 5, care este 8, și apoi echo afișează acest rezultat.
Substituția comenzii captează output-ul afișat (8 în acest caz) și îl atribuie
variabilei rezultat.

Variabila specială $@
Reprezintă un array cu toți parametrii poziționali (argumentele) transmiși
funcției, începând de la primul. Fiecare argument este tratat ca un șir de
caractere separat, ceea ce înseamnă că dacă funcția este apelată cu mai multe
argumente, $@ le va include pe toate, păstrând intactă orice spațiere sau ghilimele
utilizate.

Variabila specială $#
Într-un script Bash sau într-o funcție, $# reprezintă numărul de argumente
poziționale sau parametrii transmiși scriptului sau funcției. Această variabilă
este utilă pentru a verifica dacă scriptul sau funcția a fost apelată cu numărul
corect de argumente. De exemplu, dacă un script necesită exact doi parametri pentru
a rula corect, se poate folosi $# pentru a testa acest lucru și pentru a afișa un
mesaj de eroare sau instrucțiuni de utilizare dacă numărul de argumente nu
corespunde așteptărilor.

Exemplu: Funcție pentru Verificarea Existentei unui Fișier


Copy
#!/bin/bash

verifica_fisier() {
if [ -e "$1" ]; then
echo "Fișierul $1 există."
else
echo "Fișierul $1 nu există."
fi
}

# Verificarea mai multor fișiere


verifica_fisier "/path/to/fisier1.txt"
verifica_fisier "/path/to/fisier2.txt"
Funcția verifica_fisier verifică dacă un fișier dat ca argument există. Este un
exemplu de cum poți încapsula logica de verificare într-o funcție reutilizabilă.

Avantajele Folosirii Funcțiilor


Reutilizarea Codului: Odată definită, o funcție poate fi apelată în multiple locuri
din script, evitând duplicarea codului.

Organizarea Codului: Funcțiile ajută la împărțirea scripturilor în blocuri logice,


făcând codul mai ușor de înțeles și de întreținut.

Abstracția: Funcțiile permit abstractizarea detaliilor de implementare, astfel


încât să te poți concentra pe logica de nivel mai înalt.

Comanda return în Funcții


Comanda return este folosită într-o funcție pentru a ieși din acea funcție și
opțional, pentru a returna un cod de ieșire (status de ieșire) către shell. Codul
de ieșire este un număr întreg între 0 și 255, unde 0 indică de obicei succes, iar
orice altă valoare indică un tip de eroare sau stare specifică. return nu
returnează o valoare în sensul clasic al programării, ci mai degrabă stabilește
statusul de ieșire al funcției.

Exemplu de utilizare return:


Copy
codeverifica_fisier() {
if [ -e "$1" ]; then
echo "Fișierul există."
return 0
else
echo "Fișierul nu există."
return 1
fi
}

verifica_fisier "/path/to/fisier"
echo "Cod de ieșire: $?"
În acest exemplu, return 0 indică faptul că fișierul există (succes), în timp ce
return 1 indică faptul că fișierul nu există (o formă de eroare sau condiție de
eșec). $? este o variabilă specială care păstrează codul de ieșire al ultimei
comenzi executate.

Variabila Specială $0
Variabila $0 reprezintă numele scriptului care este executat. În contextul unei
funcții, $0 va continua să reprezinte numele scriptului întreg, nu numele funcției.

Exemplu de utilizare $0:

Copy
echo "Acest script se numește $0."
Dacă acest cod este parte dintr-un script numit script.sh și executi scriptul, va
afișa:

Copy
Acest script se numește script.sh.
Indiferent unde este folosită în script, $0 va referi întotdeauna la numele
scriptului inițial executat, nu la funcțiile apelate în cadrul scriptului.

Exemplu funcție calcul factorial


Calculul factorialului unui număr prin recursivitate în Bash poate fi realizat
printr-o funcție care se apelează pe ea însăși până când ajunge la cazul de bază.
Factorialul unui număr
n
n, notat ca
n
!
n!, este produsul tuturor numerelor naturale pozitive mai mici sau egale cu
n
n. Matematic, acesta este definit ca:

n
!
=
n
×
(
n

1
)
×
(
n

2
)
×

×
2
×
1
n!=n×(n−1)×(n−2)×…×2×1

0
!
=
1
0!=1 prin definiție

Script Bash pentru Calculul Factorialului


Copy
#!/bin/bash

factorial() {
if [ $1 -le 1 ]; then
echo 1
else
prev=$(factorial $(($1 - 1)))
echo $(($1 * prev))
fi
}

# Exemplu de utilizare
read -p "Introduceți un număr pentru a calcula factorialul: " numar
if [[ $numar =~ ^[0-9]+$ ]]; then
rezultat=$(factorial $numar)
echo "Factorialul lui $numar este: $rezultat"
else
echo "Vă rugăm să introduceți un număr întreg pozitiv."
fi
Cum Funcționează Scriptul
Definirea Funcției factorial: Funcția factorial este definită pentru a calcula
factorialul unui număr. Ea primește un argument ($1), care este numărul pentru care
se calculează factorialul.

Cazul de Bază: Dacă argumentul este mai mic sau egal cu 1, funcția returnează 1,
deoarece
0
!
=
1
0!=1 și
1
!
=
1
1!=1.

Recursivitatea: Pentru orice alt caz, funcția se apelează pe ea însăși cu


argumentul decrementat cu 1. Rezultatul acestui apel recursiv este stocat în
variabila prev, iar apoi se calculează produsul dintre numărul curent și rezultatul
apelului recursiv, care este returnat.

Utilizarea Funcției: Scriptul citește un număr de la utilizator, verifică dacă


acesta este un număr întreg pozitiv, apoi apelează funcția factorial cu acest număr
și afișează rezultatul.

Notă
Bash nu este optimizat pentru recursivitate profundă și poate fi ineficient sau
limitat pentru calculul factorialului unor numere foarte mari. Pentru astfel de
calcule, limbaje de programare precum Python sau C++ sunt mai potrivite.

Prelucrarea textelor in Bash


Lucrul cu șiruri de caractere în Bash include diverse operațiuni precum
manipularea, testarea și extragerea datelor din șiruri. Iată câteva dintre cele mai
frecvente operațiuni pe șiruri de caractere în Bash, împreună cu exemple de cod:

1. Concatenarea Șirurilor de Caractere


Pentru a concatena două sau mai multe șiruri, pur și simplu plasați-le unul lângă
altul:

Copy
str1="Hello"
str2="World"
result="$str1 $str2"
echo "$result" # Outputs: Hello World
2. Determinarea Lungimii unui Șir
Puteți obține lungimea unui șir de caractere folosind ${#string}:

Copy
str="Hello"
echo "${#str}" # Outputs: 5
3. Extragerea Subșirurilor
Extragerea unui subșir se poate face utilizând sintaxa ${string:start:length}, unde
start este indicele de început (bazat pe zero), iar length este numărul de
caractere de extras:

Copy
str="Hello World"
substring="${str:6:5}"
echo "$substring" # Outputs: World
4. Înlocuirea în Șiruri
Pentru a înlocui text într-un șir, folosiți ${string/old/new} pentru a înlocui
prima apariție sau ${string//old/new} pentru a înlocui toate aparițiile:

Copy
str="Hello World World"
modified="${str//World/There}"
echo "$modified" # Outputs: Hello There There
5. Compararea Șirurilor de Caractere
Compararea șirurilor de caractere se poate face folosind operatorii de condiție în
structuri if sau în bucle. Exemplu de verificare dacă două șiruri sunt egale:

Copy
str1="Hello"
str2="World"
if [ "$str1" = "$str2" ]; then
echo "Strings are equal."
else
echo "Strings are not equal."
fi
6. Testarea Prezenței unui Subșir
Bash oferă modalități de a testa dacă un subșir este prezent într-un șir:

Copy
str="Hello World"
if [[ "$str" == *"World"* ]]; then
echo "Substring found."
else
echo "Substring not found."
fi
7. Iterarea peste Caracterele unui Șir
Puteți itera peste fiecare caracter al unui șir folosind o buclă for:

Copy
str="Hello"
for (( i=0; i<${#str}; i++ )); do
echo "${str:$i:1}"
done
Aceste exemple acoperă operațiunile de bază cu șiruri de caractere în Bash, însă
Bash oferă și alte funcționalități avansate, precum lucrul cu expresii regulate,
care pot fi integrate în scripturi pentru manipularea și procesarea textelor
complexe.

Sed
Comanda sed (Stream Editor) este un utilitar puternic în Bash pentru manipularea
textului în fluxuri de date și fișiere. Acesta este folosit frecvent pentru
substituție, ștergere, inserare și alte operațiuni de procesare a textului. Iată
câteva exemple comune care ilustrează cum să folosești sed în Bash:

1. Substituirea Textului
Cel mai comun caz de utilizare pentru sed este substituirea textului într-un fișier
sau flux. Pentru a înlocui toate aparițiile unui text cu altul:

Copy
echo "Hello World" | sed 's/World/There/'
Acest exemplu afișează "Hello There". Pentru a modifica un fișier direct, adăugați
opțiunea -i care modifică fișierul "in-place":

Copy
sed -i 's/old-text/new-text/g' filename.txt
Opțiunea g la sfârșitul pattern-ului de substituție indică faptul că toate
aparițiile textului trebuie înlocuite, nu doar prima.

2. Ștergerea Liniilor
sed poate fi folosit pentru a șterge linii care corespund unui anumit criteriu. De
exemplu, pentru a șterge toate liniile care conțin cuvântul "delete":

Copy
sed '/delete/d' filename.txt
Pentru a șterge linia a 3-a dintr-un fișier:

Copy
sed '3d' filename.txt
3. Adăugarea de Text
Puteți adăuga text înainte sau după o anumită linie folosind sed. De exemplu,
pentru a adăuga "New Line" înainte de a 5-a linie:

Copy
sed '5iNew Line' filename.txt
Pentru a adăuga text după linia:

Copy
sed '5aNew Line' filename.txt
4. Extragerea unor Secțiuni de Text
Utilizând sed, puteți extrage anumite porțiuni de text bazate pe numărul liniei:

Copy
sed -n '1,5p' filename.txt
Acesta comandă afișează liniile de la 1 la 5 din fișierul dat. Opțiunea -n suprimă
afișarea implicită a datelor, iar p indică sed să afișeze acele linii.

5. Modificarea Delimitatorului de Pattern


Dacă textul conține multe slash-uri /, poate fi util să schimbați delimitatorul
pentru a face comanda mai lizibilă:

Copy
echo "path/to/file" | sed 's|path/to|new/path/to|'
Aici, delimitatorul este schimbat din / în |, ceea ce face comanda mai ușor de
citit și evită necesitatea de a face "escape" pentru caracterele /.

6. Utilizarea Multilinie în sed


sed poate fi folosit pentru a efectua operațiuni care implică mai multe linii. De
exemplu, pentru a înlocui un text care se întinde pe mai multe linii:

Copy
sed '/start_pattern/,/end_pattern/s/old/new/g' filename.txt
7. Înlocuirea unei secvențe dintre două caractere utilizând sed
Această comandă caută un bloc de text care se găsește în a 3a pereche de caractere
delimitate de caracterul , și înlocuiește cu șirul kiwi.

Copy
fruits='apple,banana,orange,mango,grapefruit,strawberry'
echo $fruits | sed -E 's/^(([^,]*,){3})[^,]*/\1kiwi/'
# apple,banana,orange,kiwi,grapefruit,strawberry

echo $fruits | sed -E 's/^([^,]*,){4}([^,]*),.*/\2/'


# sterge tot conținutul mai puțin ce se găsește în a 4a pereche delimitată de
virgulă
# grapefruit
Aceste exemple ilustrează flexibilitatea și puterea utilitarului sed în manipularea
textelor în Bash, oferind o gamă largă de opțiuni pentru editarea eficientă a
datelor în scripturi automate.

AWK este un limbaj de programare și un utilitar puternic pentru procesarea și


analiza textului în sistemele Unix/Linux, ideal pentru manipularea datelor
structurate (cum ar fi tabele sau structuri CSV). Acesta poate citi și procesa
fiecare linie dintr-un fișier sau flux de intrare, folosind un model de programare
orientat pe înregistrări și câmpuri, unde fiecare linie este tratată ca o
înregistrare și fiecare fragment de date delimitat (de exemplu, de spațiu sau alt
delimitator specificat) dintr-o linie este tratat ca un câmp. AWK este folosit
extensiv pentru a extrage și afișa specific câmpurile de date, pentru operații de
sumare, filtrare și transformare a datelor, și pentru generarea rapoartelor.
Comenzile AWK sunt construite din modele și acțiuni, unde modelele determină care
linii din text sunt afectate de acțiunile specificate, făcându-l extrem de util în
scenarii de scripting și pentru comenzi one-liner.

Mai multe detalii sunt disponibile la:


https://www.gnu.org/software/gawk/manual/gawk.pdf

Expresii regulate
Expresiile regulate (sau regex, de la Regular Expressions) sunt șiruri de caractere
care formează un pattern de căutare, folosite pentru a identifica, căuta, și
manipula textul bazat pe anumite modele. Acestea sunt extrem de puternice și
flexibile, fiind utilizate în programare, procesarea textelor, analiza datelor, și
în diverse utilitare de sistem pentru a efectua operații complexe pe texte, cum ar
fi căutări, înlocuiri, și validări de format.

Expresiile regulate pot fi folosite în multe limbaje de programare (cum ar fi Perl,


Python, Java, JavaScript, C#, etc.), în linia de comandă Unix/Linux (de exemplu, cu
utilitare ca grep, sed, awk), și în multe alte contexte.

Componentele Principale ale Expresiilor Regulate:


Caractere literale: Căutarea unui caracter exact, cum ar fi a sau 7.

Metacaractere: Caractere speciale care au un sens aparte în contextul unei expresii


regulate. Exemple includ . (orice caracter), ^ (începutul liniei), $ (sfârșitul
liniei), * (zero sau mai multe apariții ale caracterului precedent), + (una sau mai
multe apariții), ? (zero sau o apariție), și altele.

Seturi de caractere: Specificate între paranteze pătrate [ ], permit căutarea


oricărui caracter din set. De exemplu, [a-z] se potrivește cu orice literă mică.

Grupuri și intervaluri: Parantezele ( ) definesc grupuri, iar parantezele pătrate


cu - definesc intervaluri de caractere.

Caractere de escape: Folosirea backslash-ului \ pentru a indica că următorul


caracter este un metacaracter care trebuie tratat ca un caracter literal, de
exemplu, \. pentru a căuta un punct.

Exemple de Expresii Regulate:


^abc: Se potrivește cu orice șir de caractere care începe cu abc.

abc$: Se potrivește cu orice șir de caractere care se termină cu abc.

[A-Za-z]: Se potrivește cu orice literă, mare sau mică.

[0-9]+: Se potrivește cu un șir de una sau mai multe cifre.

a|b: Se potrivește cu a sau b.

(abc)+: Se potrivește cu unul sau mai multe secvențe ale șirului abc.

\d: (în unele limbaje/mediuri) Se potrivește cu orice cifră; echivalent cu [0-9].

Expresiile regulate sunt un instrument extrem de puternic, dar complexitatea lor


poate varia semnificativ, de la pattern-uri simple la unele extrem de complicate.
Eficiența utilizării lor vine din capacitatea de a descrie și executa operații pe
texte cu un nivel înalt de precizie și flexibilitate. Învățarea și stăpânirea
expresiilor regulate poate semnificativ îmbunătăți eficiența lucrului cu text într-
o varietate largă de aplicații și contexte.

Expresiile regulate, în combinație cu sed (Stream Editor), oferă o modalitate


puternică de a manipula textul în scripturile Bash. Iată câteva exemple complexe de
utilizare a expresiilor regulate și sed pentru a efectua operații avansate de
procesare a textului:
Exemplu 1: Înlocuirea textului condiționată
Să presupunem că dorești să înlocuiești cuvântul "error" cu "warning" doar în
liniile care conțin cuvântul "critical":

Copy
echo -e "This is a critical error in the system\nThis is an error in the
application" | sed '/critical/s/error/warning/'
Acesta comandă utilizează expresia regulată pentru a căuta liniile care conțin
"critical" și apoi aplică substituția de "error" cu "warning" doar pe acele linii.

Exemplu 2: Ștergerea liniilor care nu corespund unui pattern


Dacă ai un fișier de log și vrei să elimini toate liniile care nu conțin cuvântul
"ERROR":

Copy
sed '/ERROR/!d' filename.log
Aici, ! este folosit pentru a nega pattern-ul, astfel d (delete) se aplică tuturor
liniilor care nu conțin "ERROR".

Exemplu 3: Extragerea și formatarea datelor


Să presupunem că ai un fișier cu date de contact și dorești să extragi și să
reformatezi numerele de telefon:

Copy
echo "John Doe; Address: Some Location; Phone: 123-456-7890" | sed -n 's/.*Phone: \
([0-9\-]\+\).*/\1/p'
Acesta comandă folosește paranteze pentru a crea un grup de capturare pentru
numărul de telefon și \1 pentru a referi primul grup de capturare în înlocuire,
astfel afișând doar numărul de telefon.

Exemplu 4: Adăugarea textului condiționat la sfârșitul unei linii


Dacă dorești să adaugi " [CHECKED]" la sfârșitul fiecărei linii care conține
"TODO":

Copy
sed '/TODO/s/$/ [CHECKED]/' filename.txt
Acesta comandă caută liniile care conțin "TODO" și adaugă " [CHECKED]" la sfârșitul
fiecărei astfel de linii, folosind $ pentru a indica sfârșitul liniei.

Exemplu 5: Modificarea liniilor bazate pe condiții numerice


Modificarea liniilor bazate pe numărul lor, de exemplu, adăugarea unui antet la
primele 5 linii:

Copy
sed '1,5s/^/Header: /' filename.txt
Acesta comandă adaugă "Header: " la începutul fiecărei linii de la 1 la 5.

Există mai multe tipuri de expresii regulate (regex), fiecare cu propriile sale
caracteristici și sintaxă, adaptate pentru diferite limbaje de programare și
unelte. Pentru contextul curent, prezintă relevanță:

POSIX Basic Regular Expressions (BRE)


Este suportată de unelte Unix/Linux tradiționale precum sed și grep. Sintaxa BRE
este mai simplă și mai restrictivă. De exemplu, în BRE, metacaracterele ca +, ?, și
| nu au nicio semnificație specială decât dacă sunt precedate de un backslash (\).

Mai multe detalii la:


https://en.wikibooks.org/wiki/Regular_Expressions/POSIX_Basic_Regular_Expressions
Execuția Asincronă în Bash
Execuția asincronă permite rularea unui proces fără a bloca terminalul sau shell-
ul, permițând utilizatorului să continue alte activități în timp ce procesul este
încă în derulare.

Exemplu:

Copy
echo "Start long process..."
sleep 10 &
echo "Continuing with other commands..."
În acest exemplu:

Comanda sleep 10 & este executată în background, ceea ce înseamnă că nu va bloca


shell-ul pentru 10 secunde.

Mesajul "Continuing with other commands..." va fi afișat imediat după ce comanda


sleep este trimisă în background, fără să aștepte finalizarea ei.

Execuția Concurentă în Bash


Execuția concurentă implică rularea simultană a mai multor procese, care pot
partaja resursele CPU într-un mod care pare că sunt procesate în același timp, deși
de cele mai multe ori sunt multiplexate rapid de către sistemul de operare.

Exemplu:

Copy
for i in {1..5}
do
(sleep $i; echo "Finished sleep $i") &
done
echo "All sleep commands are running in the background."
În acest exemplu:

Bucla for lansează cinci comenzi sleep, fiecare cu durate diferite (sleep 1, sleep
2, ..., sleep 5), și fiecare comandă este executată în background.

Fiecare comandă sleep afișează un mesaj când se finalizează, iar ordinea afișării
acestor mesaje depinde de durata fiecărei comenzi sleep.

Mesajul "All sleep commands are running in background." este afișat imediat după ce
toate comenzile sleep sunt inițiate, demonstrând concurența.

Exemplu:

Copy
#!/bin/bash
sleepy() {
sleep 5
echo $1
pidof $0 #Comanda pidof este utilizată pentru a afișa ID-ul procesului al
procesului curent executat. $0 într-un script Bash se referă la numele scriptului
însuși.
return
}

for ((i=0; i<5; i++))


do
sleepy $i &
done
Ordinea variabilă în care sunt afișate valorile lui $i din multiplele execuții ale
funcției sleepy executate în background este o consecință directă a naturii
asincrone și concurente a executării proceselor în sistemul de operare.

Când rulezi funcții sau comenzi în background în Bash (utilizând &), fiecare
comandă este lansată într-un proces separat de către shell. Aceste procese rulează
în paralel cu procesul principal și între ele. Sistemul de operare gestionează
aceste procese în mod independent, alocând timp de procesor în funcție de
disponibilitate și de prioritățile proceselor, care pot varia din diverse motive,
cum ar fi încărcarea sistemului și alți factori de scheduling intern.

Deoarece fiecare proces (în cazul acesta, fiecare execuție a funcției sleepy) poate
fi inițiat și programat independent de celelalte, nu există nicio garanție că vor
termina în ordinea în care au fost inițiate. De exemplu, chiar dacă sleepy 0 este
lansat primul, el poate fi preemtat de procesor, iar sleepy 1 sau sleepy 2 pot
obține acces la procesor și pot finaliza execuția înaintea lui sleepy 0.

De asemenea, întrucât comanda sleep 5 suspendă execuția fiecărui proces pentru


exact același interval de timp, mici diferențe în momentul inițierii sau în
comportamentul scheduler-ului pot duce la finalizarea proceselor într-o ordine
diferită de fiecare dată când rulezi scriptul.

În contextul execuției scripturilor de Bash sau al programării în general, termenul


„fork” se referă la procesul prin care un proces în execuție (cunoscut sub numele
de proces părinte) creează o copie a sa (numită proces copil). Această acțiune este
realizată prin apelul sistemului de operare fork(), disponibil în sistemele de
operare de tip Unix și Linux.

Funcționalitatea fork:
Când un proces apelează fork(), sistemul de operare creează un nou proces. Noul
proces este aproape o copie identică a procesului părinte, inclusiv:

Codul programului

Datele

Valoarea variabilelor

Contorul de program (program counter)

Deschiderea fișierelor (file descriptors) și alte resurse de sistem

Diferența majoră este că procesul copil are un nou ID unic de proces (PID). De
asemenea, unele resurse, cum ar fi semafoarele sau conexiunile de rețea, nu sunt
împărțite între procesul părinte și cel copil.

În Bash, când execuți o comandă în background folosind operatorul &, Bash folosește
fork pentru a crea un nou proces copil care să execute comanda, permițând shell-
ului să continue rularea altor comenzi fără a aștepta finalizarea comenzii lansate
în background.

Exemplu:
Copy
#!/bin/bash

echo "Acesta este procesul părinte cu PID $$"


echo "Se lansează un proces copil..."
some_command & # Se execută `some_command` în background
pid=$!
echo "Procesul copil are PID $pid"
wait $pid # Așteaptă finalizarea procesului copil
echo "Procesul copil a terminat execuția."
În acest script:

$$ este o variabilă specială în Bash care stochează PID-ul procesului curent


(părinte).

Operatorul & lansează comanda some_command în background, ceea ce înseamnă că se


face un fork.

$! este o variabilă specială în Bash care stochează PID-ul ultimului proces lansat
în background.

Folosirea fork este esențială pentru multitasking și execuția concurentă în


sistemele Unix-like, permițând scripturilor și aplicațiilor să efectueze multiple
sarcini simultan sau să continue rularea în timp ce așteaptă finalizarea unui
proces copil.

Considerații pentru Concurență


Deși execuția concurentă poate îmbunătăți eficiența prin utilizarea simultană a
resurselor, ea poate introduce complexități suplimentare, cum ar fi condiții de
întrecere și probleme de sincronizare. Acest lucru este important de luat în
considerare în scenarii unde ordinea de execuție este critică sau unde procesele
accesează și modifică resurse partajate.

Prin urmare, atunci când scrii scripturi Bash care folosesc execuția asincronă sau
concurentă, este esențial să înțelegi și să planifici pentru aceste potențiale
probleme, asigurându-te că scriptul tău funcționează corect în toate scenariile
anticipate.

Source
Comanda source în Bash este utilizată pentru a executa un script în contextul
shell-ului curent. În loc să pornească un nou sub-shell pentru a rula scriptul,
comanda source încarcă și execută conținutul scriptului direct în shell-ul curent.
Acest lucru permite oricăror variabile sau funcții definite în script să rămână
disponibile în shell-ul curent după terminarea executării scriptului.

Utilizări tipice ale comenzii source:


Inițializarea mediului: source este frecvent folosită pentru a inițializa
variabilele de mediu sau pentru a executa scripturi de configurare care pregătesc
mediul de lucru. De exemplu, în multe sisteme, fișierele precum ~/.bashrc sau
~/.profile sunt încărcate automat la pornirea unui nou shell interactiv, dar dacă
se fac modificări la aceste fișiere, pot fi aplicate imediat prin rularea source
~/.bashrc.

Testarea scripturilor: Dacă dezvolți un script care definește funcții sau


variabile, poți folosi source pentru a-l încărca și a testa comportamentul acestuia
fără a fi nevoie să închizi și să redeschizi shell-ul.

Exemplu de utilizare:
Pentru a demonstra, să presupunem că ai un script numit setenv.sh care setează
variabilele de mediu necesare pentru un proiect:

Copy
# Conținutul fișierului setenv.sh
export PROJECT_PATH="/path/to/project"
export DB_USER="username"
export DB_PASS="password"
Pentru a încărca acest script în shell-ul tău curent, ai folosi:

Copy
source setenv.sh
După executarea acestei comenzi, variabilele PROJECT_PATH, DB_USER, și DB_PASS vor
fi disponibile în shell-ul tău curent. Poți verifica acest lucru folosind echo
$PROJECT_PATH, care ar trebui să afișeze calea specificată.

Comanda source poate fi, de asemenea, invocată folosind punctul (.) ca un alias.
Următorul exemplu face același lucru ca și comanda source de mai sus:

Copy
. setenv.sh
Utilizarea comenzii source este esențială pentru lucrul eficient în Bash, permițând
modificări rapide și dinamice ale mediului de lucru fără a restarta shell-ul sau a
pierde starea curentă.

Execuția unui script cu argumente


call_sum_script.sh
Copy
#!/bin/bash
# Script părinte care apelează al doilea script cu două argumente numerice.
./sum_script.sh 27 132
sum_script.sh
Copy
#!/bin/bash
# Verificăm dacă au fost furnizate exact două argumente.
if [ $# -ne 2 ]; then
echo "Eroare. Scriptul se apelează: $0 number1 number2"
exit 1
fi

# Calculăm suma celor două argumente numerice.


sum=$(($1 + $2))

# Afișăm suma.
echo "Suma dintre $1 și $2 este $sum"
Copy
./call_sum_script.sh
Suma dintre 27 și 132 este 159

S-ar putea să vă placă și