Differences

This shows you the differences between two versions of the page.

Link to this comparison view

uso:cursuri:curs-11 [2016/01/03 19:59]
razvan.deaconescu
uso:cursuri:curs-11 [2022/12/20 01:54] (current)
sergiu.weisz
Line 1: Line 1:
-====== Curs 11 - Prelucrarea datelor ​=======+====== Curs 11 - Automatizarea sarcinilor ​=======
  
-  * [[http://​elf.cs.pub.ro/​uso/​res/​cursuri/​curs-11/curs-11-handout.pdf | Slide-uri curs]] +  ​* [[https://​docs.google.com/​presentation/​d/​1c9fhDF-nGlf8w7EwU5s7hb4T-QLzpiXL/​edit?​usp=sharing&​ouid=108131427433094834232&​rtpof=true&​sd=true|Slide-uri curs]] 
-  * [[http://​elf.cs.pub.ro/​uso/​res/​cursuri/​curs-11/curs-11-handout-4on1-notes.pdf | Handout 4on1 and notes space]] +  * **Suport de curs** 
-  * [[http://​elf.cs.pub.ro/​uso/​res/​cursuri/​curs-11/curs-11-handout-8on1.pdf | Handout 8on1]] +    * [[https://​github.com/​systems-cs-pub-ro/​carte-uso/​releases | Utilizarea sistemelor de operare]] 
-  * **Cuvinte cheie**: ​dateprelucrare//means////ends//parsareprezentaredate tabelare, separator de câmpuri, ''​cut'',​ ''​awk'',​ ''​IFS'',​ ''​while read'',​ expresii regulate, metacaractere,​ ''​grep'', ​shell scripting, ''​for'',​ ''​if'',​ rezultate numericegrafice+        * Secțiunea 13 - Automatizarea sarcinilor 
 + 
 +<​HTML>​ 
 +<​center>​ 
 +<iframe src="​https://​docs.google.com/​presentation/​d/​e/​2PACX-1vRkkdapnVGRS-63NUGpc4uuPSERscZiDp2_jyWIF3qvbG_j5wO9UluTeitc99AjPw/​embed?​start=false&​loop=false&​delayms=3000"​ frameborder="​0"​ width="​480"​ height="​389"​ allowfullscreen="​true"​ mozallowfullscreen="​true"​ webkitallowfullscreen="​true"></​iframe>​ 
 +</​center>​ 
 +</​HTML>​ 
 + 
 +===== Demo-uri ===== 
 + 
 +Pentru rularea demo-urilor de mai jos folosim [[http://​repository.grid.pub.ro/​cs/​uso/​USO%20Demo.ova|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: 
 +  - Folosim direct consola mașinii virtuale. 
 +  - 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<​code>​ 
 +ssh student@<​adresa-IP-vm-eth1>​ 
 +</​code>​ 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<​code>​ 
 +sudo su - 
 +</​code>​ 
 +obținem permisiuni privilegiate (de ''​root''​) în shell. 
 + 
 +<​note>​ 
 +Dacă dorim să ne conectăm pe SSH iar mașina virtuală nu are adresă IP configurată pe interfața ''​eth1''​ atunci folosim comanda<​code>​ 
 +sudo dhclient eth1 
 +</​code>​ 
 +pentru a obține o adresă IP. 
 +</​note>​ 
 + 
 +<​note>​ 
 +Dacă optăm pentru rularea prin SSH iar sistemul fizic rulează Windows, putem folosi [[http://​www.chiark.greenend.org.uk/​~sgtatham/​putty/​|Putty]] pe post de client SSH pe sistemul fizic. 
 +</​note>​ 
 + 
 +<​note>​ 
 +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. 
 +</​note>​ 
 + 
 +==== Prelucrare note ==== 
 + 
 +Pentru acest scenariu, actualizați [[https://​github.com/​systems-cs-pub-ro/​uso-lab|repository-ul public de USO]] și navigați în subdirectorul ''​lectures/​auto/​grades/'':​ 
 + 
 +<code bash> 
 +student@uso:​~$ cd uso-lab 
 +student@uso:​~/​uso-lab$ git pull 
 +student@uso:​~/​uso-lab$ cd lectures/​auto/​grades 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ ls 
 +2016-2017.csv ​ 2017-2018.csv ​ 2018-2019.csv ​ 2019-2020.csv ​ script.wiki ​ show_average_final ​ show_average_final_series ​ show_nums ​ stats.py 
 +</​code>​ 
 + 
 +Directorul conține fișiere CSV (//Comma Separated Values//) reprezentând cataloagele anonimizate de la cursul de USO din ultimii ani: 2016-2017, 2017-2018, 2018-2019, 2019-2020. 
 +Ne propunem să facem prelucrarea acestora. 
 + 
 +Pentru început, să aflăm câți studenți au participat la curs în fiecare an. Folosim utilitarul ''​wc'':​ 
 + 
 +<code bash> 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ wc -l 2016-2017.csv 
 +494 2016-2017.csv 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ wc -l 2017-2018.csv 
 +538 2017-2018.csv 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ wc -l 2018-2019.csv 
 +542 2018-2019.csv 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ wc -l 2019-2020.csv 
 +532 2019-2020.csv 
 +</​code>​ 
 + 
 +Ne dorim o afișare mai aspectuoasă și care să elimine și linia de tip header a fișierului CSV. 
 +Pentru aceasta construim un one-liner:​ 
 +<code bash> 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ tail -n +2 2019-2020.csv | wc -l 
 +531 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ echo -n "​2019-2020:​ " ; tail -n +2 2019-2020.csv | wc -l 
 +2019-2020: 531 
 +</​code>​ 
 +Am folosit utilitarul ''​tail''​ ca să eliminăm din afișare headerul fișierului. 
 +Am folosit operatorul pipe (''​|''​) ca să filtrăm apoi rezultatul prin utilitarul ''​wc''​. 
 + 
 +Am putea rula o comandă precum cea de mai sus pentru toate cele patru fișiere. 
 +Dar ar trebui să modificăm pe rând fiecare an universitar. 
 +Vrem o variantă mai eficientă, care să permită inclusiv "​scalarea"​ la apariția unor fișiere pentru alți ani. 
 +Pentru aceasta construim un nou one-liner care să folosească ''​for''​ pentru a parcurge fișierele CSV: 
 +<code bash> 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ for i in *.csv; do echo -n "​$(basename "​$i"​ .csv): " ; tail -n +2 "​$i"​ | wc -l; done 
 +2016-2017: 493 
 +2017-2018: 537 
 +2018-2019: 541 
 +2019-2020: 531 
 +</​code>​ 
 +Acum, oricând avem nevoie de aceste informații,​ folosim one linerul. 
 + 
 +Desigur, nu ne oprim aici, ci vrem informații la nivelul fiecărei serii. 
 +Am putea realiza acest lucru tot cu un one-liner, ca mai jos, adăugând încă o secvență ''​for''​ care parcurge cele patru serii (''​CA'',​ ''​CB'',​ ''​CC'',​ ''​CD''​):​ 
 +<code bash> 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ for year in *.csv; do for series in CA CB CC CD; do echo -n "​$(basename "​$year"​ .csv) - $series: " ; tail -n +2 "​$year"​ | grep "​$series"​ | wc -l; done; done 
 +2016-2017 - CA: 109 
 +2016-2017 - CB: 137 
 +2016-2017 - CC: 111 
 +2016-2017 - CD: 170 
 +2017-2018 - CA: 155 
 +2017-2018 - CB: 147 
 +2017-2018 - CC: 151 
 +2017-2018 - CD: 143 
 +2018-2019 - CA: 161 
 +2018-2019 - CB: 137 
 +2018-2019 - CC: 156 
 +2018-2019 - CD: 136 
 +2019-2020 - CA: 130 
 +2019-2020 - CB: 136 
 +2019-2020 - CC: 145 
 +2019-2020 - CD: 131 
 +</​code>​ 
 + 
 +Deja one-linerul este complicat. 
 +Este momentul să tranzităm la folosirea unui script, care e mai ușor de citit, de modificat, de utilizat și de menținut. 
 +Folosim scriptul ''​show_nums'':​ 
 +<code bash> 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ cat ./​show_nums 
 +#​!/​bin/​bash 
 + 
 +if test $# -ne 1; then 
 +    echo "​Usage:​ $0 <​csv_file>"​ 1>&​2 
 +    exit 1 
 +fi 
 + 
 +csv_file="​$1"​ 
 +if test ! -f "​$csv_file";​ then 
 +    echo "​Error:​ Argument $csv_file is not a file." 1>&​2 
 +    exit 1 
 +fi 
 + 
 +for series in CA CB CC CD; do 
 +    echo -n "​$series:​ " 
 +    tail -n +2 "​$csv_file"​ | grep "​$series"​ | wc -l 
 +    for group in 311 312 313 314 315; do 
 +        echo -n "​$group$series:​ " 
 +        tail -n +2 "​$csv_file"​ | grep "​$group$series"​ | wc -l 
 +    done 
 +done 
 + 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ ./​show_nums 
 +Usage: ./show_nums <​csv_file>​ 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ ./show_nums 2016-2017.csv 
 +CA: 109 
 +311CA: 28 
 +312CA: 27 
 +313CA: 27 
 +314CA: 27 
 +315CA: 0 
 +CB: 137 
 +311CB: 27 
 +312CB: 28 
 +313CB: 28 
 +314CB: 27 
 +315CB: 27 
 +CC: 111 
 +310CC: 27 
 +312CC: 28 
 +313CC: 28 
 +314CC: 28 
 +315CC: 0 
 +CD: 170 
 +311CD: 26 
 +312CD: 27 
 +313CD: 26 
 +314CD: 27 
 +315CD: 27 
 + 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ ./show_nums 2017-2018.csv 
 +[...] 
 + 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ ./show_nums 2018-2019.csv 
 +[...] 
 + 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ ./show_nums 2019-2020.csv 
 +[...] 
 + 
 +</​code>​ 
 +Scriptul ''​show_nums''​ primește ca argument chiar numele fișierului CSV. 
 +Parcurge fișierul și afișează informații la nivel de serie. 
 + 
 +Numărul de studenți este o informație relativ simplă. 
 +O informație mai valoroasă, pentru evaluarea disciplinei,​ a subiectelor și a pregătirii studenților,​ o reprezintă notele. 
 +Vrem să extragem media studenților. 
 +Pentru aceasta putem folosi one-linere și construcții shell: 
 +<code bash> 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ tail -n +2 2016-2017.csv | cut -d','​ -f3 | grep -v '​^$'​ | paste -s -d'​+'​ | bc 
 +3657.0 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ sum=$(tail -n +2 2016-2017.csv | cut -d','​ -f3 | grep -v '​^$'​ | paste -s -d'​+'​ | bc) 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ count=$(tail -n +2 2016-2017.csv | wc -l) 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ echo "​scale=2;​ $sum/​$count"​ 
 +scale=2; 3657.0/​493 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ echo "​scale=2;​ $sum/​$count"​ | bc 
 +7.41 
 +</​code>​ 
 +Obținem că media notelor finale în anul universitar 2016-2017 este ''​7.41''​. 
 +Media este eronată: este media pentru toți studenții inclusiv cei absenți; variabila ''​count''​ nu a eliminat studenții absenți. 
 +O medie calculată corect este: 
 +<code bash> 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ count=$(tail -n +2 2016-2017.csv | cut -d ','​ -f3 | grep -v '​^$'​ | wc -l) 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ echo "​scale=2;​ $sum/​$count"​ | bc 
 +7.96 
 +</​code>​ 
 +În secvența de mai sus, am eliminat intrările care nu conțin valoare (notele absente), la fel cum am procedat și în calculul sumei ''​sum''​. 
 + 
 +În plus, one-linerul nu este robust. 
 +Este posibil ca unele intrări să conțină șirul ''​ABS''​ sau ''​absent'',​ așa cum vedem că este cazul fișierului ''​2017-2018.csv'':​ 
 +<code bash> 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ tail -n +2 2017-2018.csv | cut -d','​ -f3 | grep -v '​^$'​ | paste -s -d'​+'​ 
 +9.0+9.0+9.0+8.0+8.0+8.0+10.0+9.0+6.0+7.0+9.0+4.0+10.0+10.0+9.0+8.0+9.0+9.0+6.0+6.0+10.0+9.0+9.0+10.0+9.0+10.0+5.0+10.0+8.0+10.0+10.0+10.0+7.0+10.0+10.0+8.0+9.0+8.0+9.0+10.0+9.0+6.0+10.0+10.0+8.0+10.0+7.0+7.0+8.0+10.0+8.0+7.0+9.0+8.0+9.0+10.0+10.0+10.0+9.0+7.0+6.0+10.0+10.0+6.0+9.0+8.0+8.0+10.0+10.0+7.0+10.0+9.0+8.0+10.0+10.0+8.0+10.0+10.0+9.0+8.0+9.0+7.0+6.0+8.0+9.0+10.0+6.0+6.0+8.0+7.0+7.0+8.0+9.0+9.0+6.0+9.0+8.0+9.0+10.0+6.0+10.0+10.0+8.0+10.0+8.0+10.0+9.0+10.0+10.0+10.0+8.0+10.0+10.0+10.0+8.0+9.0+6.0+10.0+5.0+10.0+10.0+10.0+10.0+5.0+9.0+8.0+8.0+7.0+9.0+7.0+8.0+9.0+7.0+7.0+9.0+6.0+7.0+6.0+7.0+7.0+9.0+8.0+10.0+7.0+8.0+10.0+10.0+10.0+9.0+5.0+10.0+10.0+9.0+10.0+10.0+8.0+10.0+6.0+7.0+10.0+10.0+6.0+8.0+10.0+10.0+absent+9.0+7.0+9.0+8.0+9.0+8.0+6.0+4.0+10.0+9.0+10.0+8.0+8.0+7.0+9.0+8.0+10.0+10.0+7.0+9.0+9.0+8.0+7.0+7.0+8.0+7.0+8.0+7.0+10.0+6.0+7.0+8.0+9.0+10.0+5.0+7.0+6.0+9.0+6.0+7.0+6.0+8.0+8.0+9.0+8.0+absent+9.0+6.0+10.0+10.0+10.0+6.0+9.0+6.0+7.0+8.0+6.0+10.0+6.0+9.0+absent+absent+10.0+7.0+8.0+absent+7.0+8.0+9.0+8.0+9.0+9.0+6.0+absent+9.0+10.0+absent+10.0+10.0+9.0+10.0+8.0+8.0+7.0+8.0+8.0+10.0+absent+8.0+10.0+6.0+7.0+8.0+10.0+10.0+10.0+8.0+9.0+9.0+absent+7.0+10.0+8.0+9.0+7.0+10.0+9.0+6.0+8.0+10.0+7.0+7.0+10.0+10.0+10.0+10.0+10.0+8.0+7.0+8.0+8.0+10.0+10.0+8.0+10.0+9.0+8.0+9.0+10.0+9.0+7.0+8.0+9.0+9.0+10.0+6.0+9.0+10.0+8.0+10.0+10.0+6.0+10.0+9.0+9.0+7.0+8.0+7.0+7.0+10.0+ABS+4.0+9.0+10.0+10.0+7.0+ABS+10.0+7.0+9.0+10.0+10.0+10.0+10.0+10.0+10.0+10.0+9.0+8.0+8.0+10.0+10.0+10.0+9.0+9.0+9.0+5.0+10.0+8.0+10.0+8.0+8.0+10.0+8.0+ABS+ABS+10.0+8.0+7.0+10.0+10.0+9.0+10.0+9.0+8.0+7.0+10.0+10.0+7.0+10.0+10.0+10.0+8.0+7.0+9.0+10.0+9.0+10.0+10.0+10.0+10.0+10.0+7.0+9.0+ABS+10.0+ABS+4.0+8.0+6.0+8.0+10.0+10.0+6.0+7.0+8.0+9.0+9.0+10.0+9.0+8.0+9.0+8.0+9.0+8.0+8.0+9.0+5.0+10.0+7.0+5.0+10.0+8.0+9.0+10.0+8.0+6.0+10.0+8.0+10.0+8.0+8.0+8.0+7.0+9.0+10.0+7.0+8.0+9.0+9.0+7.0+absent+5.0+7.0+7.0+7.0+10.0+8.0+9.0+6.0+10.0+10.0+10.0+8.0+4.0+7.0+10.0+7.0+7.0+8.0+7.0+5.0+6.0+5.0+6.0+10.0+absent+9.0+7.0+9.0+10.0+9.0+7.0+10.0+7.0+6.0+10.0+7.0+6.0+9.0+9.0+absent+7.0+10.0+7.0+10.0+7.0+7.0+8.0+7.0+8.0+6.0+absent+7.0+9.0+7.0+6.0+7.0+absent+6.0+4.0+8.0+absent+8.0+8.0+7.0+9.0+7.0+10.0+8.0+6.0+8.0+9.0+10.0+6.0+10.0+4.0+7.0+absent+10.0+10.0+9.0+4.0+8.0+9.0+absent+7.0+8.0+6.0+8.0+5.0+9.0+8.0+6.0+7.0+8.0+7.0+10.0+9.0+7.0+7.0+6.0+9.0+10.0+9.0+8.0+7.0+10.0+10.0+7.0+10.0 
 +</​code>​ 
 + 
 +Ținând cont de aceasta, creăm scriptul ''​show_average_final''​ care rezolvă problemele de mai sus, și care împrumută bunele practici ale scriptului ''​show_num''​ ca să afișeze media fiecărui an universitar:​ 
 +<code bash> 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ ./​show_average_final 2016-2017.csv 
 +7.96 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ ./​show_average_final 2017-2018.csv 
 +8.33 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ ./​show_average_final 2018-2019.csv 
 +8.77 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ ./​show_average_final 2019-2020.csv 
 +7.85 
 +</​code>​ 
 + 
 +Dacă ne dorim statistici și la nivelul seriei, actualizăm scriptul în scriptul ''​show_average_final_series'':​ 
 +<code bash> 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ ./​show_average_final_series 2019-2020.csv 
 +7.85 
 +CA: 8.17 
 +CB: 8.50 
 +CC: 7.74 
 +CD: 7.10 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ ./​show_average_final_series 2018-2019.csv 
 +8.77 
 +CA: 8.76 
 +CB: 8.39 
 +CC: 8.94 
 +CD: 8.84 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ ./​show_average_final_series 2017-2018.csv 
 +8.33 
 +CA: 8.68 
 +CB: 8.18 
 +CC: 8.57 
 +CD: 7.88 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ ./​show_average_final_series 2016-2017.csv 
 +7.96 
 +CA: 8.42 
 +CB: 7.94 
 +CC: 7.81 
 +CD: 7.86 
 +</​code>​ 
 + 
 +În momentul în care efectuăm prelucrări numerice și pe date din ce în ce mai multe și cu potențiale noi cerințe de prelucrarea,​ ne gândim să trecem la un limbaj de scripting / programare cu mai multe funcționalități de prelucrare numerică și de șiruri, care să permită o mai bună mentenanță. 
 +Un astfel de exemplu este scriptul ''​stats.py''​ în Python: 
 +<code bash> 
 +student@uso:​~/​uso-lab/​lectures/​auto/​grades$ python stats.py 
 +Grup           ​Număr ​   Notă    Quiz    Teme Midterm Practic 
 +2016-2017 ​       455    7.96    6.40    7.71    6.52    7.00 
 +CA               ​105 ​   8.42    6.94    7.65    6.75    8.01 
 +CB               ​123 ​   7.94    6.14    7.88    5.92    7.17 
 +CC               ​105 ​   7.82    6.01    7.42    7.01    6.83 
 +CD               ​122 ​   7.72    6.52    7.84    6.51    6.11 
 + 
 +2017-2018 ​       503    8.36    6.01    9.25    7.42    7.19 
 +CA               ​117 ​   8.64    6.71    9.27    7.09    7.13 
 +CB               ​134 ​   8.26    5.46    9.17    7.10    7.67 
 +CC               ​118 ​   8.74    6.86    9.33    7.87    7.57 
 +CD               ​134 ​   7.89    5.22    9.25    7.62    6.42 
 + 
 +2018-2019 ​       498    8.78    6.86    8.98    7.52    8.23 
 +CA               ​131 ​   8.82    6.97    8.93    7.52    8.76 
 +CB               ​122 ​   8.39    6.42    8.97    7.12    6.74 
 +CC               ​124 ​   9.02    7.05    9.15    7.43    8.67 
 +CD               ​121 ​   8.86    6.99    8.87    8.03    8.71 
 + 
 +2019-2020 ​       488    8.14    5.93    8.69    6.67    6.97 
 +CA               ​121 ​   8.31    6.12    8.62    6.69    7.80 
 +CB               ​125 ​   8.50    6.69    8.63    6.92    7.80 
 +CC               ​126 ​   8.07    6.26    8.61    6.80    6.06 
 +CD               ​116 ​   7.65    4.54    8.90    6.25    6.19 
 + 
 +</​code>​ 
 + 
 +În acest script facem o prelucrare a tuturor notelor: final, examen grilă, teme, examen practic final și de midterm. 
 +Scriptul folosește funcționalități ale limbajului Python: clase, dicționare,​ funcții, parcurgerea fișierelor (CSV). 
 +Aceste lucruri îl fac ușor de actualizat și de meținut. 
 + 
 +Concluzionând,​ atunci când facem automatizare:​ 
 +  * folosim funcționalități existente ale shellului 
 +  * pornim cu înlănțuiri de comenzi și one linere 
 +  * pe măsură ce avansăm, trecem la scripturi shell 
 +  * când prelucrăm șiruri sau numere și avem multe date și cerințe în creștere, tranzităm la un limbaj de scripting / programare (precum Python) 
 + 
 + 
 +/* 
 + 
 +====== Curs 10 - Securitatea sistemului ======= 
 + 
 +  * [[https://​drive.google.com/​open?​id=1R-pS_BAVlEy4mHS3Zjf9h7X13fSVlCgr|Slide-uri curs]] 
 +  * [[https://​drive.google.com/​file/​d/​1k2YOlX247w5aGUt0ptmwHTOZ6CFZEoXh/​view?​usp=sharing|Handouts 3on1 and notes space]] 
 +  * [[https://​drive.google.com/​file/​d/​1G-j69EsOEepRE1v3102gUa1OG65UgbgP/​view?​usp=sharing|Handouts 6on1]] 
 +  * **Cuvinte cheie**:  
 +  * **Suport de curs** 
 +    * [[http://​elf.cs.pub.ro/​uso/​res/​carte/​uso_cap-12-sec.pdf|Capitolul 12: Securitatea sistemului]] 
 +    * [[http://​books.google.com/​books?​id=_JFGzyRxQGcC | Introducere în sisteme de operare]] 
 +      * [[http://​books.google.com/​books?​id=_JFGzyRxQGcC&​pg=PA279 | Capitolul 10 - Elemente de securitate]] 
 + 
 +===== Demo-uri ===== 
 + 
 +Pentru rularea demo-urilor de mai jos folosim [[http://​repository.grid.pub.ro/​cs/​uso/​USO%20Demo.ova|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: 
 +  - Folosim direct consola mașinii virtuale. 
 +  - 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<​code>​ 
 +ssh student@<​adresa-IP-vm-eth1>​ 
 +</​code>​ 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<​code>​ 
 +sudo su - 
 +</​code>​ 
 +obținem permisiuni privilegiate (de ''​root''​) în shell. 
 + 
 +<​note>​ 
 +Dacă dorim să ne conectăm pe SSH iar mașina virtuală nu are adresă IP configurată pe interfața ''​eth1''​ atunci folosim comanda<​code>​ 
 +sudo dhclient eth1 
 +</​code>​ 
 +pentru a obține o adresă IP. 
 +</​note>​ 
 + 
 +<​note>​ 
 +Dacă optăm pentru rularea prin SSH iar sistemul fizic rulează Windows, putem folosi [[http://​www.chiark.greenend.org.uk/​~sgtatham/​putty/​|Putty]] pe post de client SSH pe sistemul fizic. 
 +</​note>​ 
 + 
 +<​note>​ 
 +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. 
 +</​note>​ 
 + 
 +==== Folosire umask pentru configurarea permisiunilor de creare ==== 
 + 
 +Unul dintre cele mai importante principii în securitate este principiul celui mai mic privilegiu (//least privilege//​). Pentru aceasta, inclusiv în sistemul de fișiere (fișiere, directoare),​ se recomandă permisiuni (drepturi de acces minime). Acestea pot fi schimbate folosind comanda ''​chmod''​. Dorim, însă, să putem configura permisiunile implicite la crearea intrărilor în sistemul de fișiere. Pentru aceasta folosim comanda ''​umask''​. 
 + 
 +La o rulare simplă, comanda ''​umask''​ ne afișează valoarea sa:<​code>​ 
 +student@uso-demo:​~$ umask 
 +0022 
 +</​code>​ 
 +Comanda ''​umask''​ indică permisiunile care vor fi **absente** în momentul creării unor intrări. Regulile de stabilire a permisiunilor de creare sunt: 
 +  * pentru fișiere: 666 & ~umask (adică 666 **ȘI logic** cu masca negată) 
 +  * pentru directoare: 777 & ~umask (adică 777 **ȘI logic** cu masca negată) 
 + 
 +Pentru ''​umask = 0022'',​ ''​~umask = 7755''​. Rezultă permisiunile de creare: 
 +  * pentru fișiere: ''​666 & 7755 = 0644''​ 
 +  * pentru directoare: ''​777 & 7755 = 0755''​ 
 + 
 +Putem verifica acest lucru creând un fișier și un director:<​code>​ 
 +student@uso-demo:​~$ touch test-file 
 +student@uso-demo:​~$ mkdir test-dir 
 +student@uso-demo:​~$ ls -l 
 +total 4 
 +drwxr-xr-x 2 student student 4096 Jan  5 11:31 test-dir 
 +-rw-r--r-- 1 student student ​   0 Jan  5 11:31 test-file 
 +</​code>​ 
 +Observăm că fișierul (''​test-file''​) a fost creat cu permisiunile ''​%%rw-r--r--%%''​ (adică ''​644''​) iar directorul (''​test-dir''​) a fost creat cu permisiunile ''​%%rwxr-xr-x%%''​ (adică ''​755''​). Adică valorile așteptate. 
 + 
 +În ideea de //least privilege//,​ este uzual să oferim permisiuni doar utilizatorului (''​user''​) și nici o permisiune pentru ''​group''​ și ''​others''​. Pentru aceasta stabilim valoarea ''​umask''​ la ''​077'',​ folosind comanda<​code>​ 
 +student@uso-demo:​~$ umask 077 
 +student@uso-demo:​~$ umask 
 +0077 
 +</​code>​ 
 +Observăm din a doua comandă că acum valoarea ''​umask''​ este alta. 
 + 
 +Creăm un nou fișier și un nou director și verificăm aplicarea noii valori a ''​umask''​ pentru stabilirea permisiunilor de creare:<​code>​ 
 +student@uso-demo:​~$ touch test-file-2 
 +student@uso-demo:​~$ mkdir test-dir-2 
 +student@uso-demo:​~$ ls -l  
 +total 8 
 +drwxr-xr-x 2 student student 4096 Jan  5 11:31 test-dir 
 +drwx------ 2 student student 4096 Jan  5 11:36 test-dir-2 
 +-rw-r--r-- 1 student student ​   0 Jan  5 11:31 test-file 
 +-rw------- 1 student student ​   0 Jan  5 11:36 test-file-2 
 +</​code>​ 
 +Observăm că fișierul (''​test-file-2''​) a fost creat cu permisiunile ''​%%rw-------%%''​ (adică ''​600''​) iar directorul (''​test-dir''​) a fost creat cu permisiunile ''​%%rwx------%%''​ (adică ''​700''​). Adică valorile așteptate, rezultate în urma calculului:​ 
 +  * pentru fișier: ''​%%666 & ~umask = 666 & ~0077 = 666 & 7700 = 600 = rw-------%%''​ 
 +  * pentru director: ''​%%777 & ~umask =777 & ~0077 = 777 & 7700 = 700 = rwx------%%''​ 
 + 
 +Valoarea ''​umask''​ este configurată funcție de nevoile utilizatorului ținând cont și de principiul celui mai mic privilegiu. 
 + 
 +<​note>​ 
 +Valoarea ''​umask''​ este pe 4 cifre în octal. Prima cifră este aferentă biților speciali (''​setuid'',​ ''​setgid'',​ ''​sticky''​) folosiți în permisiuni. Nu insistăm pe acest lucru. Puteți găsi informații în secțiunile aferente din [[http://​man7.org/​linux/​man-pages/​man1/​chmod.1.html|pagina de manual a chmod]]. 
 +</​note>​ 
 + 
 +<​note>​ 
 +Pentru configurarea persistentă a valorii ''​umask''​ se recomandă plasarea comenzii de configurare într-un fișier de configurare a sesiunii de shell (precum ''​~/​.bashrc''​). 
 +</​note>​ 
 +==== Folosire John the Ripper pentru password cracking ==== 
 + 
 +Din perspectiva atacatorului (sau a unui [[http://​www.computerhope.com/​jargon/​e/​ethihack.htm|hacker etic]]) este util să putem "​sparge"​ parolele dintr-un sistem. Dacă ajungem să avem acces la baza de date cu parole a unui sistem putem încerca spargerea acestora. Un utilitar pentru acest lucru este [[http://​www.openwall.com/​john/​|John the Ripper]]. 
 + 
 +Pentru a folosi ''​john''​ întâi îl vom instala:<​code>​ 
 +student@uso-demo:​~$ sudo apt-get install john 
 +Reading package lists... Done 
 +Building dependency tree        
 +[...] 
 +Setting up john-data (1.8.0-2) ... 
 +Setting up john (1.8.0-2) ... 
 +</​code>​ 
 + 
 +John vine în mod implicit cu un dicționar de parole comune de folosit în fișierul ''/​usr/​share/​john/​password.lst''<​code>​ 
 +student@uso-demo:​~$ head -20 /​usr/​share/​john/​password.lst  
 +#!comment: This list has been compiled by Solar Designer of Openwall Project 
 +#!comment: in 1996 through 2011.  It is assumed to be in the public domain. 
 +#​!comment:​ 
 +#!comment: This list is based on passwords most commonly seen on a set of Unix 
 +#!comment: systems in mid-1990'​s,​ sorted for decreasing number of occurrences 
 +#!comment: (that is, more common passwords are listed first). ​ It has been 
 +#!comment: revised to also include common website passwords from public lists 
 +#!comment: of "top N passwords"​ from major community website compromises that 
 +#!comment: occurred in 2006 through 2010. 
 +#​!comment:​ 
 +#!comment: Last update: 2011/11/20 (3546 entries) 
 +#​!comment:​ 
 +#!comment: For more wordlists, see http://​www.openwall.com/​wordlists/​ 
 +123456 
 +12345 
 +password 
 +password1 
 +123456789 
 +12345678 
 +1234567890 
 +student@uso-demo:​~$ wc -l /​usr/​share/​john/​password.lst 
 +3559 /​usr/​share/​john/​password.lst 
 +</​code>​ 
 +Există fișiere de parole mai bune care, în general, costă bani. 
 + 
 +Aceste parole sunt parole frecvente folosite de utilizatori și care pot fi ușor sparte cu John. 
 + 
 +Pentru verificare, să creăm doi utilizatori (''​ana''​ și ''​bogdan''​) cu parole relativ comune ''​test123''​ și ''​qazwsx'':<​code>​ 
 +student@uso-demo:​~$ sudo useradd -m -d /home/ana -s /bin/bash ana 
 +student@uso-demo:​~$ sudo useradd -m -d /​home/​bogdan -s /bin/bash bogdan 
 +student@uso-demo:​~$ less /​usr/​share/​john/​password.lst 
 +student@uso-demo:​~$ echo "​ana:​test123"​ | sudo chpasswd 
 +student@uso-demo:​~$ echo "​bogdan:​qazwsx"​ | sudo chpasswd 
 +student@uso-demo:​~$ id ana 
 +uid=1001(ana) gid=1001(ana) groups=1001(ana) 
 +student@uso-demo:​~$ id bogdan 
 +uid=1002(bogdan) gid=1002(bogdan) groups=1002(bogdan) 
 +</​code>​ 
 + 
 +Mai sus am creat cei doi utilizatori cu parolele dorite. 
 + 
 +<​note>​ 
 +Comanda ''​chpasswd''​ este o comandă care schimbă/​actualizează parola unuia sau mai mulți utilizatori. Parola primește la intarea standard linii în forma ''<​username>:<​password>''​ și actualizează parola utilizatorului ''<​username>''​ cu valoarea ''<​password>''​. 
 +</​note>​ 
 + 
 +Parolele utilizatorilor sunt stocate în forma criptată (//hash//) în fișierul ''/​etc/​shadow'',​ accesibil doar cu permisiuni privilegiate<​code>​ 
 +student@uso-demo:​~$ tail -2 /​etc/​shadow 
 +tail: cannot open ‘/​etc/​shadow’ for reading: Permission denied 
 +student@uso-demo:​~$ ls -l /​etc/​shadow 
 +-rw-r----- 1 root shadow 1276 Jan  5 11:59 /​etc/​shadow 
 +student@uso-demo:​~$ sudo tail -2 /​etc/​shadow 
 +ana:​$6$Lz4VGpO.$NhGn3XzSJ8dRd.EURfPRnPPlU3rvTG5C7xEvvh8taiPCLEFb0V2LAFG.6s.GlXWZqby326wvZm91QMDoCXCoU0:​16805:​0:​99999:​7:::​ 
 +bogdan:​$6$AJ8cjSHz$QdI1KrolofQtAk4F2bHweL7vxzGYcM3gHxfLgRiUzR7UtEugUZyWARc66zo8YMEiMmAWob5PJMlaoUyA8rfCx.:​16805:​0:​99999:​7:::​ 
 +</​code>​ 
 +Dacă avem acces la hash-urile parolelor putem încerca spargerea lor cu John. În cazul de față vom reuși pentru că parolele sunt foarte simple:<​code>​ 
 +student@uso-demo:​~$ sudo tail -2 /etc/shadow > shadow-entries 
 +student@uso-demo:​~$ cat shadow-entries  
 +ana:​$6$Lz4VGpO.$NhGn3XzSJ8dRd.EURfPRnPPlU3rvTG5C7xEvvh8taiPCLEFb0V2LAFG.6s.GlXWZqby326wvZm91QMDoCXCoU0:​16805:​0:​99999:​7:::​ 
 +bogdan:​$6$AJ8cjSHz$QdI1KrolofQtAk4F2bHweL7vxzGYcM3gHxfLgRiUzR7UtEugUZyWARc66zo8YMEiMmAWob5PJMlaoUyA8rfCx.:​16805:​0:​99999:​7:::​ 
 + 
 +student@uso-demo:​~$ /​usr/​sbin/​john -wordlist:/​usr/​share/​john/​password.lst shadow-entries 
 +Created directory: /​home/​student/​.john 
 +Loaded 2 password hashes with 2 different salts (crypt, generic crypt(3) [?/32]) 
 +Press '​q'​ or Ctrl-C to abort, almost any other key for status 
 +test123 ​         (ana) 
 +qazwsx ​          ​(bogdan) 
 +2g 0:00:00:33 100% 0.05959g/s 62.93p/s 71.51c/s 71.51C/s pretty..celtic 
 +Use the "​--show"​ option to display all of the cracked passwords reliably 
 +Session completed 
 +</​code>​ 
 +Mai sus, pentru început, am extras cele două intrări din ''/​etc/​shadow''​ și apoi am folosit John ca să încercăm spargerea lor. În mod așteptat, parolele fiind simple, John a reușit spargerea lor. 
 + 
 +În general, un atacator va încerca să obțină accesul la baza de date cu parole. Chiar dacă acestea sunt criptate, atacatorul va încerca să le spargă. Doar parolele puternice (cu multe caractere dintr-un set mai mare) pot supraviețui suficient de mult timp unui atacator. Chiar și așa, se recomandă actualizarea parolelor după o perioadă de 6 luni sau 1 an. 
 + 
 +<​note>​ 
 +John are diverse opțiuni care permit scheme de alterare a parolelor din wordlist-uri. Aceste scheme prelungesc posibilitățile de parole încercate; de exemplu înlocuirea ''​a''​ cu ''​@''​ sau ''​e''​ cu ''​3''​. Cu un word list bun, multe parole pot fi sparte relativ rapid. 
 +</​note>​ 
 +==== Criptare/​decriptare folosind chei simetrice ==== 
 + 
 +Pentru securizarea informației transmise sau stocate este recomandat ca aceasta să fie criptată. În Internet, foarte multe site-uri folosesc acum ''​HTTPS''​ (HTTP securizat). Pentru date locale se pot folosi utilitare de criptare. 
 + 
 +Un utilitar folosit pentru criptare (și alte operații criptografice) este ''​openssl''​. Cu ''​openssl''​ putem cripta și folosind chei simetrice și chei asimetrice. 
 + 
 +Pentru testare, să creăm un fișier //plain text// (ușor de citit):<​code>​ 
 +student@uso-demo:​~$ echo "This is my life's biggest secret: I have no life" > plain.txt 
 +student@uso-demo:​~$ cat plain.txt  
 +This is my life's biggest secret: I have no life 
 +</​code>​ 
 + 
 +Pentru a cripta accest fișier, folosim algoritmul ''​AES''​ (//Advanced Encryption Standard//​),​ un standard de facto de criptare, cu ajutorul comenzii<​code>​ 
 +student@uso-demo:​~$ openssl enc -e -aes-256-cbc -in plain.txt -out encrypted.dat 
 +enter aes-256-cbc encryption password: 
 +Verifying - enter aes-256-cbc encryption password: 
 +student@uso-demo:​~$ ls -l encrypted.dat  
 +-rw------- 1 student student 80 Jan  5 12:17 encrypted.dat 
 +student@uso-demo:​~$ xxd encrypted.dat  
 +0000000: 5361 6c74 6564 5f5f 6b32 c1b2 6580 bcfe  Salted__k2..e... 
 +0000010: f988 bd4d 4432 9aa3 8925 0097 4262 1732  ...MD2...%..Bb.2 
 +0000020: 119a c5c8 f5de bca0 3a9e 4d96 57c7 1e1f  ........:​.M.W... 
 +0000030: 3e22 e8ec eeec 3905 4e93 3ee8 fb5e c04a  >"​....9.N.>​..^.J 
 +0000040: e443 955f c693 7171 fa10 f5ac ded1 f947  .C._..qq.......G 
 +</​code>​ 
 +În prima comandă am realizat criptarea fișierului ''​plain.txt''​ în fișierul ''​encrypted.dat''​. Utilitarul ne-a cerut cheia de criptare și apoi a realizat criptarea în fișierul ''​encrypted.dat''​. Fișierul este un fișier binar; putem urmări conținutul său folosind comanda ''​xxd''​. 
 + 
 +De obicei vom șterge fișierul ''​plain.txt''​ și apoi vom decripta, la nevoie, fișierul ''​encrypted.dat''​. Facem acest lucru folosind comenzile de mai jos<​code>​ 
 +student@uso-demo:​~$ rm plain.txt  
 +student@uso-demo:​~$ openssl enc -d -aes-256-cbc -in encrypted.dat -out plain.txt 
 +enter aes-256-cbc decryption password: 
 +student@uso-demo:​~$ cat plain.txt  
 +This is my life's biggest secret: I have no life 
 +</​code>​ 
 +Observăm că, după ștergerea fișierului //plain text// inițial, și după operația de decriptare căreia i-am transmis cheia folosită la pasul anterior, am obținut fișierul inițial. 
 + 
 +<​note>​ 
 +Sunt și alți algoritmi posibili pentru criptare simetrică folosind comanda ''​openssl''​. Pentru a-i determina folosim comanda<​code>​ 
 +student@uso-demo:​~$ openssl enc -help 
 +</​code>​ 
 +</​note>​ 
 + 
 +Dacă dorim să stocăm fișierul criptat într-o formă de fișier text (dar tot criptat) putem realiza o codificare [[https://​en.wikipedia.org/​wiki/​Base64|base64]] a acestuia. Pentru aceasta, folosim pentru criptare și decriptare comenzile în forma de mai jos:<​code>​ 
 +student@uso-demo:​~$ openssl enc -e -base64 -aes-256-cbc -in plain.txt -out encrypted.dat 
 +enter aes-256-cbc encryption password: 
 +Verifying - enter aes-256-cbc encryption password: 
 +student@uso-demo:​~$ cat encrypted.dat  
 +U2FsdGVkX18HD7U8AkSTfWFQEryHAjfJ7hQlWZQSdMvmdwZSES76zQz7JioIultg 
 +x4sLDHbAA6xTo8ioX3gG/​L+7REMUuN46hUXCBB+G1c4= 
 + 
 +student@uso-demo:​~$ openssl enc -d -base64 -aes-256-cbc -in encrypted.dat -out plain.txt 
 +enter aes-256-cbc decryption password: 
 +student@uso-demo:​~$ cat plain.txt  
 +This is my life's biggest secret: I have no life 
 +</​code>​ 
 + 
 +Observăm mai sus că avem o formă ASCII a fișierului criptat ''​encrypted.dat''​. 
 +==== Criptare/​decriptare folosind chei asimetrice ==== 
 + 
 +Criptarea cu chei simetrice are avantajul vitezei dar dezavantajul că trebuie știută (și partajată între cel care criptează și cel care decriptează) cheia de criptare. Mai mult, dacă acea cheie este slabă, un atacator poate sparge cheia și decripta fișierul. 
 + 
 +Criptarea cu chei asimetrice folosește cheia publică pentru criptare; oricine poate astfel cripta. Pentru decriptare se folosește cheia privată și doar cel care o deține poate decripta. 
 + 
 +Pentru aceasta, vom folosi tot utilitarul ''​openssl''​. Vom folosi algoritmul ''​RSA''​ (//​Rivest-Shamir-Adleman//​) pentru criptarea asimetrică. Pentru început vom genera cheia privată și cheia publică:<​code>​ 
 +student@uso-demo:​~$ openssl genrsa -out privkey 2048 
 +Generating RSA private key, 2048 bit long modulus 
 +......................................................+++ 
 +.....................+++ 
 +e is 65537 (0x10001) 
 +student@uso-demo:​~$ cat privkey  
 +-----BEGIN RSA PRIVATE KEY----- 
 +MIIEowIBAAKCAQEA4o1PEkzZawYItZFdxsPwA/​7kbffcDLQOSCtbdORA23uO6zk8 
 +[...] 
 +-----END RSA PRIVATE KEY----- 
 +student@uso-demo:​~$ openssl rsa -pubout -in privkey -out pubkey 
 +writing RSA key 
 +student@uso-demo:​~$ cat pubkey  
 +-----BEGIN PUBLIC KEY----- 
 +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4o1PEkzZawYItZFdxsPw 
 +A/​7kbffcDLQOSCtbdORA23uO6zk8+4WLYrc1tgh827N2qcW28UsIxaA2YlowXJu7 
 +[...] 
 +-----END PUBLIC KEY----- 
 +</​code>​ 
 + 
 +Mai sus am generat cheia privată în fișierul ''​privkey''​ și cheia publică în fișierul ''​pubkey''​. Cheia publică este derivată din cheia privată. Formatul în care sunt stocate cele 2 cheie se numește PEM (//​Privacy-enhanced Electronic Mail//). 
 + 
 +Ca să criptăm fișierul ''​plain.txt''​ folosind cheia publică din fișierul ''​pubkey'',​ vom rula comanda<​code>​ 
 +student@uso-demo:​~$ openssl rsautl -encrypt -in plain.txt -out encrypted.dat -pubin -inkey pubkey  
 + 
 +student@uso-demo:​~$ xxd encrypted.dat  
 +0000000: 97e7 bc72 4d76 708f 5b2b 7437 b698 2937  ...rMvp.[+t7..)7 
 +[...] 
 +00000f0: dfd0 3bfc f5b1 9a17 9655 2b9b e441 7bba  ..;​......U+..A{. 
 +</​code>​ 
 + 
 +Fișierul criptat este un fișier binar; îl putem vizualiza folosind comanda ''​xxd''​. 
 + 
 +Pentru a decripta fișierul ''​encrypted.dat''​ înapoi în fișierul ''​plain.txt''​ folosind cheia privată din fișierul ''​privkey''​ vom rula comanda de mai jos:<​code>​ 
 +student@uso-demo:​~$ openssl rsautl -decrypt -in encrypted.dat -out plain.txt -inkey privkey 
 +student@uso-demo:​~$ cat plain.txt  
 +This is my life's biggest secret: I have no life 
 +</​code>​ 
 + 
 +<​note>​ 
 +Cheia privată, la fel cum este cheia/​parola în criptare simetrică, trebuie ținută în siguranță. O recomandare este ca o cheie privată să fie protejată și de un passphrase. Introducerea passphrase-ului condiționează folosirea cheii private. O altă recomandare este folosirea unui [[http://​lifehacker.com/​5529133/​five-best-password-managers|Password manager]] care să rețină toate parolele și cheile în mod sigur (să nu fie scrise plain text undeva) sub protecția unui master password. 
 +</​note>​ 
 +==== Semnare/​verificare folosind chei asimetrice ==== 
 + 
 +Un alt scenariu de folosire a cheilor asimetrice este pentru semnarea unor mesaje. Semnarea se face cu ajutorul cheii private (doar posesorul are acces) iar verificarea cu ajutorul cheii publice (oricine poate verifica). De obicei se transmite mesajul în plain text dar este de știut că cel care a trimis mesajul chiar este cel care l-a trimis, și pentru aceea se atașează fișierul de tip semnătură mesajului. 
 + 
 +Vom folosi tot cheia privată ''​privkey''​ și cheia publică ''​pubkey''​ de mai sus. 
 + 
 +Pentru semnarea mesajului vom folosi<​code>​ 
 +student@uso-demo:​~$ openssl rsautl -sign -in plain.txt -out signature -inkey privkey  
 +student@uso-demo:​~$ xxd signature  
 +0000000: 910f be3f 6a47 b150 f239 8105 3d64 a60d  ...?​jG.P.9..=d.. 
 +[...] 
 +00000f0: 7ffd 183f 26e4 221f c9dc 90b5 9510 7eca  ...?&​."​.......~. 
 +</​code>​ 
 + 
 +Pentru verificarea semnăturii vom folosi comanda<​code>​ 
 +student@uso-demo:​~$ openssl rsautl -verify -in signature -pubin -inkey pubkey  
 +This is my life's biggest secret: I have no life 
 +</​code>​ 
 + 
 +<​note>​ 
 +Pentru criptare/​decriptare și semnare/​verifcare cu chei asimetrice putem folosi și suita [[https://​www.gnupg.org/​|GnuPG]] (//GNU Privacy Guard//). 
 +</​note>​ 
 + 
 +/* 
 + 
 +====== Curs 10 - Shell scripting ======= 
 + 
 +  ​* [[http://​elf.cs.pub.ro/​uso/​res/​cursuri/​curs-10/curs-10-handout.pdf | Slide-uri curs]] 
 +  * [[http://​elf.cs.pub.ro/​uso/​res/​cursuri/​curs-10/curs-10-handout-4on1-notes.pdf | Handout 4on1 and notes space]] 
 +  * [[http://​elf.cs.pub.ro/​uso/​res/​cursuri/​curs-10/curs-10-handout-8on1.pdf | Handout 8on1]] 
 +  * **Cuvinte cheie**: ​variabilevariabile de mediuescapingexpandareone linerfiltru de textscript shell, ''​IFS'',​ ''​while read'',​ ''​for'',​ ''​if'',​ expresii regulate, metacaractere, globbing, ''​grep'', ​prelucrare de dateautomatizare
   * **Suport de curs**   * **Suport de curs**
     * Suport (Introducere în sisteme de operare)     * Suport (Introducere în sisteme de operare)
Line 16: Line 644:
 <​HTML>​ <​HTML>​
   <​center>​   <​center>​
-    <iframe src="http://​docs.google.com/​viewer?​url=http://​elf.cs.pub.ro/​uso/​res/​cursuri/​curs-11/curs-11-handout.pdf&​embedded=true"​ width="​600"​ height="​480"​ style="​border:​ none;">​+    <iframe src="https://​docs.google.com/​viewer?​url=http://​elf.cs.pub.ro/​uso/​res/​cursuri/​curs-10/curs-10-handout.pdf&​embedded=true"​ width="​600"​ height="​480"​ style="​border:​ none;">​
     </​iframe>​     </​iframe>​
   </​center>​   </​center>​
Line 57: Line 685:
 ==== Obținere arhivă ==== ==== Obținere arhivă ====
  
-Pentru parcurgerea demo-urilor,​ folosim [[http://​elf.cs.pub.ro/​uso/​res/​cursuri/​curs-11/curs-11-demo.zip|arhiva aferentă]]. Descărcăm arhiva în mașina virtuală (sau în orice alt mediu Linux) folosind comanda<​code bash> +Pentru parcurgerea demo-urilor,​ folosim [[http://​elf.cs.pub.ro/​uso/​res/​cursuri/​curs-10/curs-10-demo.zip|arhiva aferentă]]. Descărcăm arhiva în mașina virtuală (sau în orice alt mediu Linux) folosind comanda<​code bash> 
-student@uso-demo:​~$ wget http://​elf.cs.pub.ro/​uso/​res/​cursuri/​curs-11/curs-11-demo.zip+student@uso-demo:​~$ wget http://​elf.cs.pub.ro/​uso/​res/​cursuri/​curs-10/curs-10-demo.zip
 [...] [...]
 </​code>​ și apoi dezarhivăm arhiva<​code bash> </​code>​ și apoi dezarhivăm arhiva<​code bash>
-student@uso-demo:​~$ unzip curs-11-demo.zip ​+student@uso-demo:​~$ unzip curs-10-demo.zip ​
 [...] [...]
 </​code>​ și accesăm directorul rezultat în urma dezarhivării<​code bash> </​code>​ și accesăm directorul rezultat în urma dezarhivării<​code bash>
-student@uso-demo:​~$ cd curs-11-demo/ +student@uso-demo:​~$ cd curs-10-demo/ 
-student@uso-demo:​~/​curs-11-demo$ ls+student@uso-demo:​~/​curs-10-demo$ ls
 user-results.csv user-results.csv
 </​code>​ </​code>​
Line 121: Line 749:
 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. 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'':<​code> +Pentru a extrage conturile care au punctaj mai mare ca 500, vom folosi scriptul ''​extract-points-500'' ​de mai jos: 
-student@uso-demo:​~/​curs-11-demo$ cat extract-points-500 ​+<file Bash extract-points-500>
 #!/bin/bash #!/bin/bash
  
Line 131: Line 759:
     fi     fi
 done < user-results.csv done < user-results.csv
 +</​file>​ 
 +Rulăm scriptul folosind comanda<​code>​
 student@uso-demo:​~/​curs-11-demo$ ./​extract-points-500 ​ student@uso-demo:​~/​curs-11-demo$ ./​extract-points-500 ​
 mihaela.croitoru mihaela.croitoru
Line 237: Line 866:
 Rezultatul este același și poate părea mai simplu să folosim ''​grep''​. Doar că ''​awk''​ permite match cu expresie regulată pe un câmp specific primit la intrare; se poate forța acest lucru și cu ''​grep''​ dar devine mai puțin clar. Rezultatul este același și poate părea mai simplu să folosim ''​grep''​. Doar că ''​awk''​ permite match cu expresie regulată pe un câmp specific primit la intrare; se poate forța acest lucru și cu ''​grep''​ dar devine mai puțin clar.
  
-În momentul în care un script ''​awk''​ devine mai complicat, poate fi plasat într-un script shell, așa cum este în fișierul ''​extract-points-500-awk'':<​code> +În momentul în care un script ''​awk''​ devine mai complicat, poate fi plasat într-un script shell, așa cum este în fișierul ''​extract-points-500-awk'':​ 
-student@uso-demo:​~/​curs-11-demo$ cat extract-points-500-awk ​+<file Bash extract-points-500-awk>
 #!/bin/bash #!/bin/bash
  
Line 247: Line 876:
     }     }
 ' < user-results.csv ' < user-results.csv
 +</​file>​ 
 +Rulăm scriptul folosind comanda<​code>​
 student@uso-demo:​~/​curs-11-demo$ ./​extract-points-500-awk student@uso-demo:​~/​curs-11-demo$ ./​extract-points-500-awk
 mihaela.croitoru,​516 mihaela.croitoru,​516
Line 344: Line 974:
 În particular, utilitarul ''​sed''​ folosește expresii regulate. Unul dintre cazurile frecvente de utilizare a ''​sed''​ este pe post de editor neinteractiv,​ care să înlocuiască (substituie) elemente de pe o linie cu alte elemente. În particular, utilitarul ''​sed''​ folosește expresii regulate. Unul dintre cazurile frecvente de utilizare a ''​sed''​ este pe post de editor neinteractiv,​ care să înlocuiască (substituie) elemente de pe o linie cu alte elemente.
  
 +Dacă dorim, de exemplu, să înlocuim toate prenumele din numele de cont nu șirul ''​aaa''​ vom folosi un one liner precum cel de mai jos:<​code>​
 +student@uso-demo:​~/​curs-11-demo$ sed '​s/​^[^\.]\+/​aaa/​g'​ < user-results.csv
 +aaa.asimionesei,​Liceul Teoretic Ștefan Odobleja,​2015-03-31 16:18:01,0
 +aaa.matei,​Colegiul Național Ion Maiorescu,​2015-03-17 11:04:49,66
 +aaa.dascalu,​Colegiul Tehnic Toma Socolescu,​None,​285
 +aaa.konnerth,​Colegiul Național Nichita Stănescu,​None,​42
 +aaa.corneanu,​Liceul Teoretic Benjamin Franklin,​2015-03-18 10:​26:​21,​247
 +[...]
 +</​code>​
 +La fel ca în cazul ''​awk''​ expresia regulată se plasează între slash-uri. Expresia regulată folosită ''​%%^[^\.]\+%%''​ face match pe începutul de linie și pe șiruri de cel puțin o literă care nu conțin punct (''​.'',​ //dot//). Adică exact pe prenumele din numele de cont.
 +
 +Dacă dorim să eliminăm prenumele (împreună cu punctul) din numele de cont vom folosi o construcție precum<​code>​
 +student@uso-demo:​~/​curs-11-demo$ sed '​s/​^[^\.]\+\.//​g'​ < user-results.csv
 +asimionesei,​Liceul Teoretic Ștefan Odobleja,​2015-03-31 16:18:01,0
 +matei,​Colegiul Național Ion Maiorescu,​2015-03-17 11:04:49,66
 +dascalu,​Colegiul Tehnic Toma Socolescu,​None,​285
 +konnerth,​Colegiul Național Nichita Stănescu,​None,​42
 +corneanu,​Liceul Teoretic Benjamin Franklin,​2015-03-18 10:​26:​21,​247
 +[...]
 +</​code>​
 +În one liner-ul de mai sus am lăsat ca șir care substituie șirul vid (adică două slash-uri consecutive). Adică înlocuim partea pe care face match expresia regulată (adică prenumele din cont și caracterul punct) cu nimic, adică o ștergem.
 +
 +O situație poate fi să fie înlocuită construcția ''​prenume.nume''​ cu ''​nume.prenume''​ în numele contului. Pentru aceasta folosim construcția<​code>​
 +student@uso-demo:​~/​curs-11-demo$ sed '​s/​^\([^\.]\+\)\.\([^\,​]\+\),/​\2.\1,/​g'​ < user-results.csv
 +asimionesei.ionut,​Liceul Teoretic Ștefan Odobleja,​2015-03-31 16:18:01,0
 +matei.laura,​Colegiul Național Ion Maiorescu,​2015-03-17 11:04:49,66
 +dascalu.alin,​Colegiul Tehnic Toma Socolescu,​None,​285
 +konnerth.dragos,​Colegiul Național Nichita Stănescu,​None,​42
 +corneanu.alexandru,​Liceul Teoretic Benjamin Franklin,​2015-03-18 10:​26:​21,​247
 +[...]
 +</​code>​
 +Expresia regulată folosită mai sus (''​%%^\([^\.]\+\)\.\([^\,​]\+\),​%%''​) o decodificăm în următoarele componente:
 +  * ''​%%^%%'':​ început de linie
 +  * ''​%%\([^\.]\+\)%%'':​ face match pe prenume, adică șirul format din cel puțin un caracter diferit de punct; reține acest șir într-o variabilă (variabila este referită prin construcția ''​%%\1%%''​)
 +  * ''​%%\.%%'':​ face match pe caracterul punct (''​.'',​ //dot//) care separă prenumele de nume în cont
 +  * ''​%%\([^\,​]\+\)%%'':​ face match pe nume, adică șirul format din cel puțin un caracter diferit de virgulă; reține acest șir într-o variabilă (variabila este referită prin construcția ''​%%\2%%''​)
 +  * ''​%%,​%%'':​ face match pe caracterul virgulă ('','',​ //comma//) care urmează după cont
 +
 +Partea de înlocuit este ''​\2.\1,''​ adică numele de cont este înlocuit cu nume, urmat de punct, urmat de prenume, urmat de virgulă, așa cum ne-am dorit.
 +
 +<​note>​
 +La fel ca în cazul ''​awk'',​ ''​sed''​ este un utilitar adecvat pentru one linere, acțiuni rapide și încorporare în shell scripting. Pentru scenarii de utilizare mai complexe, recomandăm folosirea unor limbaje dedicate precum Python, Perl, Ruby, Java, JavaScript.
 +</​note>​
 ==== Automatizare folosind shell scripting ==== ==== Automatizare folosind shell scripting ====
  
-<​code>​ +Folosirea shell scripting și a one line-erelor are, de principiu, 3 scenarii de utilizare:​ 
-\begin{frame}[fragile]{Exemplu de script shell+  * conectarea/​înlănțuirea mai multor comenzi pentru a obține un rezultat nou pentru un caz punctual de utilizare 
-  ​\begin{block}{Publicare ​slide-uri de curs USO} +  * automatizarea unei acțiuni: acțiunile pot fi repetitive și atunci o implmentare poate fi rulată de mai multe ori 
-    ​\begin{alltt}+  * prelucrarea datelor: folosind comenzi și construcții de tip filtre de text (''​cut'',​ ''​while read'',​ ''​tr'',​ ''​grep'',​ ''​sort'',​ ''​awk'',​ ''​sed''​) se prelucrează date în format text 
 + 
 +Partea de automatizare este utilă atunci când vrem să executăm o acțiune în mod repetat. Un caz de utilizare este când vrem să prelucrăm în același mod mai multe fișiere. 
 + 
 +De exemplu, având în vedere conținutul subdirectorului ''​horde/'',​ vrem să creăm copii de lucru ale fișierelor de configurare de distribuție. Fișierele de distribuție au extensia ''​.dist''​ (de exemplu ''​conf.php.dist''​);​ o copie de lucru este un fișier fără extensia ''​.dist''​ (de exemplu: ''​conf.php''​). 
 + 
 +Pentru a crea copie de lucru putem folosi următorul one liner, construit pas cu pas:<​code>​ 
 +student@uso-demo:​~/​curs-11-demo$ find horde/ -name '​*.dist'​ 
 +horde/​ingo/​config/​hooks.php.dist 
 +horde/​ingo/​config/​prefs.php.dist 
 +[...] 
 + 
 +student@uso-demo:​~/​curs-11-demo$ for f in $(find horde/ -name '​*.dist'​);​ do echo "​$f";​ done 
 +horde/​ingo/​config/​hooks.php.dist 
 +horde/​ingo/​config/​prefs.php.dist 
 +[...] 
 + 
 +student@uso-demo:​~/​curs-11-demo$ for f in $(find horde/ -name '​*.dist'​);​ do echo "${f/.dist/}"; done 
 +horde/​ingo/​config/​hooks.php 
 +horde/​ingo/​config/​prefs.php 
 +[...] 
 + 
 +student@uso-demo:​~/​curs-11-demo$ for f in $(find horde/ -name '​*.dist'​);​ do cp "​$f"​ "${f/.dist/}"; done 
 +</​code>​ 
 +În ultima comandă avem one liner-ul care creează câte o copie a fișierului de distribuție într-un fișier de lucru. Construcția ''​${f/.dist/}''​ este folosită pentru a înlocui în valoarea variabilei ''​f''​ șirul ''​.dist''​ cu nimic, adică șterge acel șir, rezultând numele fișierului fără extensia ''​.dist''​. 
 + 
 +Pentru verificare folosim comanda ''​find''​ pentru a valida existența fișierelor de lucru:<​code>​ 
 +student@uso-demo:​~/​curs-11-demo$ find horde/ -name '​*.php'​ 
 +horde/​ingo/​config/​prefs.php 
 +horde/​ingo/​config/​backends.php 
 +[...] 
 +</​code>​ 
 + 
 +One liner-ul de mai sus este util o singură dată, pentru acele fișiere și de acceea nu are sens să îl trecem într-un script pe care să îl rulăm periodic, la nevoia, ca automatizare. 
 + 
 +Un exemplu de script folosit pentru automatizare este scriptul ''​publish-slides''​ folosit pentru publicarea ​slide-urilor de cursuri ​de USO. Nu veți putea rula scriptul în absența fișierelor de suport, dar este reprezentantiv pentru ceea ce înseamnă automatizarea unei sarcini repetitive: publicarea slide-urilor cursului de USO intern în cadrul echipei (în Dropbox) și studenților. 
 +<file Bash publish-slides>​
 #!/bin/bash #!/bin/bash
  
Line 356: Line 1065:
  
 if test $# -eq 1; then if test $# -eq 1; then
-    id=$(printf "\%02g" $1)+    id=$(printf "​%02g"​ $1)
     pushd curs-$id/ > /dev/null 2>&1     pushd curs-$id/ > /dev/null 2>&1
     make all     make all
Line 365: Line 1074:
 fi fi
  
-for id in $(seq -f "\%02g" 0 13); do+for id in $(seq -f "​%02g"​ 0 13); do
     pushd curs-$id/ > /dev/null 2>&1     pushd curs-$id/ > /dev/null 2>&1
     make all     make all
Line 371: Line 1080:
     scp *handout*.pdf "​$remote_end"/​curs-$id/​     scp *handout*.pdf "​$remote_end"/​curs-$id/​
     popd > /dev/null 2>&1     popd > /dev/null 2>&1
-done \end{alltt} +done 
-  \end{block} +</file>
-\end{frame} +
-</code>+
  
-==== Prelucrarea datelor cu shell scripting ====+Scriptul compilează (folosind ''​make''​) slide-urile cursului primit ca argument, sau toate slide-urile în absența argumentelor. Folosește ''​cp''​ pentru a copia slide-urile intern echipei, în Dropbox, și folosește ''​scp''​ pentru a publica slide-urile către studenți.
  
 +*/
uso/cursuri/curs-11.1451843957.txt.gz · Last modified: 2016/01/03 19:59 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