This is an old revision of the document!


Curs 11 - Prelucrarea datelor

  • Cuvinte cheie: date, prelucrare, means, ends, parsare, prezentare, date tabelare, separator de câmpuri, cut, awk, IFS, while read, expresii regulate, metacaractere, grep, shell scripting, for, if, rezultate numerice, grafice
  • Suport de curs
    • Suport (Introducere în sisteme de operare)
      • Capitolul 12 – Shell scripting
        • Secțiunile 12.4, 12.5, 12.6, 12.9
      • Puteți descărca fișierul PDF aferent de aici.
      • Capitolul 1 – Introduction to Regular Expressions
      • Capitolul 2 – Basic Regular Expression Skills

Demo-uri

Pentru 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:

  1. Folosim direct consola mașinii virtuale.
  2. Aflăm adresa IP de pe interfața eth1 a mașinii virtuale și ne conectăm prin SSH, de pe sistemul fizic, folosind comanda
    ssh 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.

Dacă dorim să ne conectăm pe SSH iar mașina virtuală nu are adresă IP configurată pe interfața eth1 atunci folosim comanda

sudo dhclient eth1

pentru a obține o adresă IP.

Dacă optăm pentru rularea prin SSH iar sistemul fizic rulează Windows, putem folosi Putty pe post de client SSH pe sistemul fizic.

Comenzile folosite sunt de uz general. Actualizând adresele IP cu adrese potrivite, putem rula cu succes comenzile pe orice sistem sau mașină virtuală Linux.

Obținere arhivă

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.

Splitting folosind cut

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
[...]

Utilitarul cut are două opțiuni frecvent folosite:

  • opțiunea -d care precizează delimitatorul de câmpuri (field delimiter sau field separator)
  • opțiunea -f care precizează ce câmpuri/coloane dorim să extragem

Splitting folosind while read

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).

Construcția while read este folosită pentru a putea face prelucrări pe fiecare linie procesată, nu doar splitting, așa cum face comanda cut.

Splitting folosind awk

Splitting folosind Python

Splitting folosind Java

\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}

Folosire expresii regulate în grep

Folosire expresii regulate în awk

Folosire expresii regulate în sed

Folosire expresii regulate în Python

\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}

Automatizare folosind shell scripting

\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}

Prelucrarea datelor cu shell scripting

uso/cursuri/curs-11.1451839641.txt.gz · Last modified: 2016/01/03 18:47 by razvan.deaconescu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0