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:
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ă:
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ă:
Dacă scriptul se află într-un alt director, poți utiliza calea absolută:
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:
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...'
.
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.
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.
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
:
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:
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:
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 cupozitie_start
.
Exemplu de Utilizare
Să presupunem că avem următorul array:
Dacă dorim să extragem un sub-array care începe de la indicele 3 și are lungimea 4, vom folosi:
Acesta va afișa:
Dacă omiti parametrul
lungime
, se vor extrage toate elementele începând cupozitie_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
:
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ă
if
- începe testul condițional.[ condiție ]
- condiția care trebuie evaluată. Parantezele drepte[ ]
reprezintă comandatest
în Bash.then
- dacă condiția evaluată este adevărată, comenzile care urmează până laelse
saufi
vor fi executate.else
- (opțional) specifică comenzile care vor fi executate dacă condiția este falsă.fi
- încheie bloculif
.
Exemplu 1: Test simplu
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
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
.
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țiaif
.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
: șirula
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:
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:
Exemplu 3:
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:
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:
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.
2. Numărarea Fișierelor dintr-un Director
Scriptul folosește find
pentru a număra toate fișierele dintr-un anumit director.
3. Backup al unui Director
Acest script creează un arhivă (backup) tar.gz a unui director specificat și îl salvează într-un alt director.
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.
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.
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:
Sau
Exemplu: Funcție pentru Afisarea Salutului
Î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
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
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
return
în FuncțiiComanda 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
:
Î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
$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
:
Dacă acest cod este parte dintr-un script numit script.sh
și executi scriptul, va afișa:
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 , notat ca , este produsul tuturor numerelor naturale pozitive mai mici sau egale cu . Matematic, acesta este definit ca:
prin definiție
Script Bash pentru Calculul Factorialului
Cum Funcționează Scriptul
Definirea Funcției
factorial
: Funcțiafactorial
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 și .
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:
2. Determinarea Lungimii unui Șir
Puteți obține lungimea unui șir de caractere folosind ${#string}
:
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:
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:
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:
6. Testarea Prezenței unui Subșir
Bash oferă modalități de a testa dacă un subșir este prezent într-un șir:
7. Iterarea peste Caracterele unui Șir
Puteți itera peste fiecare caracter al unui șir folosind o buclă for
:
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:
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":
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":
Pentru a șterge linia a 3-a dintr-un fișier:
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:
Pentru a adăuga text după linia:
4. Extragerea unor Secțiuni de Text
Utilizând sed
, puteți extrage anumite porțiuni de text bazate pe numărul liniei:
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ă:
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
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:
7. Înlocuirea unei secvențe dintre două caractere utilizând sed
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
.
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.
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
sau7
.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 cuabc
.abc$
: Se potrivește cu orice șir de caractere care se termină cuabc
.[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 cua
saub
.(abc)+
: Se potrivește cu unul sau mai multe secvențe ale șiruluiabc
.\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":
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":
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:
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":
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:
Acesta comandă adaugă "Header: " la începutul fiecărei linii de la 1 la 5.
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:
Î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 comandasleep
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:
În acest exemplu:
Bucla
for
lansează cinci comenzisleep
, 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 comenzisleep
.Mesajul
"All sleep commands are running in background."
este afișat imediat după ce toate comenzilesleep
sunt inițiate, demonstrând concurența.
Exemplu:
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
:
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:
În acest script:
$$
este o variabilă specială în Bash care stochează PID-ul procesului curent (părinte).Operatorul
&
lansează comandasome_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
:
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 rulareasource ~/.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:
Pentru a încărca acest script în shell-ul tău curent, ai folosi:
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:
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
Last updated