This is an old revision of the document!
cut
, awk
, IFS
, while read
, expresii regulate, metacaractere, grep
, shell scripting, for
, if
, rezultate numerice, graficePentru rularea demo-urilor de mai jos folosim mașina virtuală USO Demo. Mașina virtuală (în format OVA) poate fi importată în VirtualBox. Comenzile le vom rula în cadrul mașinii virtuale.
Mașina virtuală deține două interfețe de rețea:
eth0
pentru accesul la Internet (interfață de tipul NAT)eth1
pentru comunicarea cu sistemul fizic (gazdă, host) (interfață de tipul Host-only Adapter)Pentru a rula demo-ul avem două opțiuni:
eth1
a mașinii virtuale și ne conectăm prin SSH, de pe sistemul fizic, folosind comandassh student@<adresa-IP-vm-eth1>
unde <adresa-IP-vm-eth1>
este adresa IP a interfeței eth1
din cadrul mașinii virtuale.
Pentru conectarea la mașina virtuală folosim numele de utilizator student
cu parola student
. Contul student
are permsiuni de sudo
. Folosind comanda
sudo su -
obținem permisiuni privilegiate (de root
) în shell.
eth1
atunci folosim comanda
sudo dhclient eth1
pentru a obține o adresă IP.
Pentru parcurgerea demo-urilor, folosim arhiva aferentă. Descărcăm arhiva în mașina virtuală (sau în orice alt mediu Linux) folosind comanda
student@uso-demo:~$ wget http://elf.cs.pub.ro/uso/res/cursuri/curs-11/curs-11-demo.zip [...]
și apoi dezarhivăm arhiva
student@uso-demo:~$ unzip curs-11-demo.zip [...]
și accesăm directorul rezultat în urma dezarhivării
student@uso-demo:~$ cd curs-11-demo/ student@uso-demo:~/curs-11-demo$ ls user-results.csv
Acum putem parcurge secțiunile cu demo-uri de mai jos. Vom folosi resursele din directorul rezultat în urma dezarhivării.
Pentru splitting simplu de date tabelare putem folosi utilitarul cut
. Acesta permite precizarea unui delimitator și a unui câmp sau a mai multor câmpuri (coloane) care să fie selectate din tabel.
Din fișierul user-results.csv
(format CSV – Comma Separated Values) dorim să selectăm doar numele grupurilor. Pentru aceasta selectăm doar a doua coloană și folosim separatorul ,
(virgulă) folosind comanda
student@uso-demo:~/curs-11-demo$ cut -d ',' -f 2 < user-results.csv Liceul Teoretic Ștefan Odobleja Colegiul Național Ion Maiorescu Colegiul Tehnic Toma Socolescu Colegiul Național Nichita Stănescu Liceul Teoretic Benjamin Franklin Colegiul Național I.L. Caragiale Colegiul Național Zinca Golescu [...]
Dacă dorim să “unicizăm” rezultatele și să afișăm doar numele liceelor putem conecta comanda de mai sus la o comandă sort
:
student@uso-demo:~/curs-11-demo$ cut -d ',' -f 2 < user-results.csv | sort -u Colegiul Economic Virgil Madgearu Colegiul Național Alexandru Odobescu Colegiul Național Barbu Știrbei Colegiul Național Cantemir Vodă Colegiul Național Carol I Colegiul Național Gheorghe Lazăr [...]
În urma rulării comenzii de mai sus ne sunt afișate doar numele liceelor.
Dacă ne interesează să afișăm doar identificatorii utilizatorilor și punctajele obținute, atunci folosim comanda
student@uso-demo:~/curs-11-demo$ cut -d ',' -f 1,4 < user-results.csv | head ionut.asimionesei,0 laura.matei,66 alin.dascalu,285 dragos.konnerth,42 alexandru.corneanu,247 alexandru.tittes,154 [...]
cut
are două opțiuni frecvent folosite:
-d
care precizează delimitatorul de câmpuri (field delimiter sau field separator)-f
care precizează ce câmpuri/coloane dorim să extragem
Utilitarul cut
are dezavantajul că face doar splitting și extrage câmpuri/coloane. Nu putem condiționa extragerea unor câmpuri. De exemplu, dacă dorim extragerea conturilor care au punctaj mai mare ca 500, nu vom putea folosi cut
. Putem însă folosi construcția while read
într-un script shell.
Pentru a extrage conturile care au punctaj mai mare ca 500, vom folosi scriptul extract-points-500
:
student@uso-demo:~/curs-11-demo$ cat extract-points-500 #!/bin/bash IFS=',' while read uid school date points; do if test "$points" -ge 500; then echo "$uid" fi done < user-results.csv student@uso-demo:~/curs-11-demo$ ./extract-points-500 mihaela.croitoru andreea.cismas elvis.titirca mihaela.serbana anjie.teodorescu [...]
În scriptul extract-points-500
am folosit construcția while read
pentru a face split la cele patru coloane din fișierul user-results.csv
. Separatorul (delimitatorul) l-am definit cu ajutorul variabilei IFS
(Input Field Separator) pe care am inițializat-o la ,
(virgulă). După split am folosit construcția if
pentru a afișa doar conturile utilizatorilor cu punctaj peste 500
.
Dacă dorim să afișăm și punctajul obținut (nu doar contul) atunci trebuie doar să modificăm linia de afișare (care folosește comanda echo
). Rezultatul va fi scriptul actualizat și cu rularea de mai jos:
student@uso-demo:~/curs-11-demo$ cat extract-points-500 #!/bin/bash IFS=',' while read uid school date points; do if test "$points" -ge 500; then echo "$uid,$points" fi done < user-results.csv student@uso-demo:~/curs-11-demo$ ./extract-points-500 mihaela.croitoru,516 andreea.cismas,803 elvis.titirca,501 mihaela.serbana,526 anjie.teodorescu,666 georgiana.ciobanica,1047 [...]
Dacă în output-ul de mai sus dorim să avem sortare în ordine descrescătoare a punctajului, înlănțuim o comandă sort
care să sorteze numeric, descrescător după a doua coloană
student@uso-demo:~/curs-11-demo$ ./extract-points-500 | sort -t ',' -k 2,2rn radu.dumitru5227,21433 mihaela.catai,13623 stefania.oprea,9547 alexandra.calinescu,5266 george.ungureanu,3846 dragos.totu,2040 monica.cirisanu,1815
În comanda de mai sus, comanda sort
sortează output-ul scriptului folosind ca separator virgulă (construcția -t ','
după a două coloană (construcția -k 2,2
) descrescător numeric (construcția rn
).
while read
este folosită pentru a putea face prelucrări pe fiecare linie procesată, nu doar splitting, așa cum face comanda cut
.
\begin{frame}[fragile]{Exemple \cmd{cut}} \begin{itemize} \item avantaj: simplitate \item dezavantaj: un singur caracter pe post de separator, nu poate face split pe date în care separatorul de câmpuri este un set de caractere \end{itemize} \begin{block}{Obținerea numelui de utilizator din \file{/etc/passwd}} \begin{alltt} cut -d ':' -f 1 /etc/passwd \end{alltt} \end{block} \begin{block}{Obținerea unei coloane dintr-un fișier CSV} \begin{alltt} cut -d ',' -f 3 students.csv \end{alltt} \end{block} \end{frame} \begin{frame}[fragile]{Exemple \cmd{while read}} \begin{itemize} \scriptsize \item avantaj: comandă internă în shell, flexibilă, poate fi folosită în scripturi \item dezavantaj: separatorul de câmpuri nu poate fi o expresie regulată \item folosește \texttt{IFS} (\textit{Input Field Separator}): variabilă internă pentru împărțirea câmpurilor; implicit spații albe (spațiu, tab, \textit{newline}) \end{itemize} \begin{block}{Afișarea numelor studenților care au nota peste 7} \begin{alltt} IFS=',' while read name group grade; do if test "$grade" -gt 7; then echo "Student $name, from group $group received grade $grade." fi done < students.csv \end{alltt} \end{block} \begin{block}{Afișarea mesajelor de logging din ianuarie} \begin{alltt} while read day month rest; do if test "$month" == "Jan"; then echo "$day $month $rest" fi done < /var/log/syslog \end{alltt} \end{block} \end{frame} \begin{frame}[fragile]{Exemple awk} \begin{itemize} \item avantaje: foarte flexibil, un întreg limbaj de programare, split după expresii regulate \item dezavantaj: complex \end{itemize} \begin{block}{Afișarea întâi a coloanei 2 și apoi a primei coloane dintr-un fișier CSV} \begin{alltt} awk -F ',' '{print $2 "," $1;}' students.csv \end{alltt} \end{block} \begin{block}{Afișarea în formă procentuală a unei coloane cu separator spații albe} \begin{alltt} awk -F '[ \textbackslash{}t]+' '{printf "\%4.2f\%\textbackslash{}n", $3/100;}' results.txt \end{alltt} \end{block} \end{frame}
\begin{frame}[fragile]{Exemple grep} \begin{itemize} \item folosit pentru căutare \item mai mult căutare de cuvinte, mai puțin de expresii regulate \end{itemize} \begin{block}{Eliminare linii vide} \begin{alltt} grep -v '^[ \textbackslash{}t]+$' file.txt \end{alltt} \end{block} \begin{block}{Eliminare linii care încep cu comentarii} \begin{alltt} grep -v '^[ \textbackslash{}t]*#' file.txt \end{alltt} \end{block} \end{frame} \begin{frame}[fragile]{Exemplu awk} \begin{block}{Afișează serviciile care au generat mesaje de logging pe 3 ianuarie} \begin{alltt} sudo awk -F '[ \textbackslash{}t]+' '/^Jan 3/ {print $5;}' /var/log/daemon.log \end{alltt} \end{block} \end{frame} \begin{frame}[fragile]{Exemple sed} \begin{itemize} \item folosit pentru substituții, înlocuirea unui șir cu altul \end{itemize} \begin{block}{Eliminare spații albe de la începutul liniilor} \begin{alltt} sed 's/^[ \textbackslash{}t]*//g' file.txt \end{alltt} \end{block} \begin{block}{Înlocuirea șirului text cu șirul binar pe liniile ce conțin șirul fișier} \begin{alltt} sed '/fisier/s/text/binar/g' file.txt \end{alltt} \end{block} \end{frame}
\begin{frame}[fragile]{Exemplu de script shell} \begin{block}{Publicare slide-uri de curs USO} \begin{alltt} #!/bin/bash dropbox_folder=~/Downloads/Dropbox/school/uso-shared remote_end=uso@elf.cs.pub.ro:res/current/cursuri if test $# -eq 1; then id=$(printf "\%02g" $1) pushd curs-$id/ > /dev/null 2>&1 make all cp *.pdf "$dropbox_folder"/curs-$id/ scp *handout*.pdf "$remote_end"/curs-$id/ popd > /dev/null 2>&1 exit 0 fi for id in $(seq -f "\%02g" 0 13); do pushd curs-$id/ > /dev/null 2>&1 make all cp *.pdf "$dropbox_folder"/curs-$id/ scp *handout*.pdf "$remote_end"/curs-$id/ popd > /dev/null 2>&1 done \end{alltt} \end{block} \end{frame}