Differences

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

Link to this comparison view

info1:laboratoare:06 [2020/10/07 14:05]
127.0.0.1 external edit
info1:laboratoare:06 [2020/11/24 13:03] (current)
alexandru.vochescu [Căutarea unui fișier în sistem]
Line 1: Line 1:
-===== Laboratorul ​06=====+====== Laborator ​06 - Lucrul în linia de comandă - 2 ======
  
 +====== Inspectarea sistemului de fișiere ======
  
 +===== Căutarea unui fișier în sistem =====
 +
 +De multe ori ne aflăm în situația în care căutăm un fișier pe disc: ex. doar ce am clonat un proiect de pe GitHub și vrem să inspectăm fișierele sursă pentru a putea compila și rula proiectul. Un alt exemplu poate fi că vrem să vedem cum arată fișierele de test existente în proiect; de multe ori, ințelegem mai bine proiectul doar prin simpla inspectare a testelor.
 +
 +Există două utilitare care ne permit să căutăm în cadrul sistemului de fișiere: ''​%%locate%%''​ și ''​%%find%%''​. In laboratorul anterior am discutat despre utilitarul ''​%%locate%%'',​ iar în laboratorul curent vom vorbi despre utilitarul ''​%%find%%''​. ​
 +
 +==== Utilitarul find ====
 +
 +Utilitarul ''​%%find%%''​ îndeplinește același scop: căuta în fișierele de pe sistem. ''​%%find%%''​ este un utilitar mai complex decât ''​%%locate%%''​. Acesta ne permite să căutăm fișiere după nume, permisiuni, tipul fișierelor,​ data ultimei modificări și multe altele. Inspectăm pagina de manual a utilitarului pentru a vedea cum îl putem folosi.
 +
 +<code bash>
 +student@uso:​~$ man find
 +
 +SYNOPSIS
 +       ​find ​ [-H]  [-L]  [-P]  [-D  debugopts] ​ [-Olevel] ​ [starting-point...]
 +       ​[expression]
 +</​code>​
 +La o primă vedere, ''​%%find%%''​ poate părea complex și intimidant, dar lucrurile stau foarte simplu. Folosim ''​%%find%%''​ cu sintaxa ''​%%find [starting-point] [expression]%%'',​ ca în exemplul de mai jos:
 +
 +<code bash>
 +student@uso:​~$ find . -name "​*search*"​
 +./​C/​searching
 +./​C/​searching/​linear_search.c
 +./​C/​searching/​other_binary_search.c
 +./​C/​searching/​binary_search.c
 +./​C/​searching/​modified_binary_search.c
 +./​C/​searching/​jump_search.c
 +./​C/​searching/​interpolation_search.c
 +./​C/​searching/​fibonacci_search.c
 +./​C/​searching/​ternary_search.c
 +./​C/​searching/​pattern_searc h
 +./​C/​searching/​pattern_search/​naive_search.c
 +./​C/​searching/​pattern_search/​boyer_moore_search.c
 +./​C/​searching/​pattern_search/​rabin_karp_search.c
 +./​C/​data_structures/​binary_trees/​binary_search_tree.c
 +</​code>​
 +În exemplul de mai sus observă că am folosit ca **starting-point** ''​%%.%%''​ (căutarea pleacă din directorul curent), iar ca **expression** ''​%%-name "​*search*"​%%''​.
 +
 +Utilitarul ''​%%find%%''​ folosește o expresie compusă pentru căutare. În exemplul anterior am folosit opțiunea ''​%%-name PATTERN%%''​. Exact ca în cazul utilitarului ''​%%locate%%'',​ **PATTERN** poate folosi sintaxa globbing, așa cum am făcut în exemplul de mai sus ''​%%"​*search*"​%%''​.
 +
 +<​note>​
 +
 +
 +Atunci când folosim sintaxa globbing, trebuie să fim atenți să încadrăm **PATTERN** între ''​%%"​%%''​ (ghilimele),​ așa cum am făcut în exemplul de mai sus. Trebuie să facem asta pentru ca sintaxa globbing să fie interpretată de către utilitarul ''​%%find%%''​ și nu de către terminalul (''​%%bash%%''​) din care lansăm utilitarul.
 +</​note>​
 +
 +=== Scenarii complexe de căutare ===
 +
 +Utilitarul ''​%%find%%''​ are o lungă listă de opțiuni pe care le putem folosi în expresii de căutare. Una din opțiunile mai cunoscute este ''​%%-type%%''​ care ne oferă posibilitatea de a căuta după tipul unui fișier:
 +
 +<code bash>
 +student@uso:​~$ find workspace/C -type f
 +workspace/​C/​leetcode/​src/​226.c
 +workspace/​C/​leetcode/​src/​700.c
 +workspace/​C/​leetcode/​src/​278.c
 +[...]
 +</​code>​
 +În exemplul de mai sus i-am transmis utilitarului ''​%%find%%''​ că vrem să căutăm în directorul ''​%%~/​workspace/​C%%''​ toate fișierele text (regular file) ''​%%-type f%%''​.
 +
 +**Exercițiu:​** Accesați pagina de manual a utilitarului find (''​%%man find%%''​) și căutați opțiunea ''​%%-type%%''​. Căutați în directorul ''​%%workspace/​C%%''​ după fiecare tip de fișier pentru care oferă suport opțiunea ''​%%-type%%''​.
 +
 +<​note>​
 +
 +
 +Reminder: pentru a căuta în man folosim ''​%%/​%%''​ pentru a intra în search mode și apoi introducem textul pe care îl căutam ''​%%-type%%''​ urmat de tasta ''​%%Enter%%'';​ pentru a ne duce la următorul rezultat al căutării folosim tasta ''​%%n%%''​ (next).
 +</​note>​
 +
 +În cadrul unei căutări putem să combinăm opțiunile de căutare:
 +
 +<code bash>
 +student@uso:​~$ find workspace/C -type f -name "​*search*"​
 +workspace/​C/​searching/​modified_binary_search.c
 +workspace/​C/​searching/​ternary_search.c
 +workspace/​C/​searching/​jump_search.c
 +workspace/​C/​searching/​binary_search.c
 +</​code>​
 +În exemplul de mai sus căutăm toate fișierele text care conțin șirul **search** în nume.
 +
 +Utilitarul ''​%%find%%''​ ne permite să executăm comenzi asupra rezultatelor căutării. Facem acest cu opțiunea ''​%%-exec command {} ;​%%''​. Atunci când folosim ''​%%-exec%%'',​ rezultatul căutării va înlocui șirul **'​{}'​** în textul comenzii; comanda de executat trebuie să se termine în caracterul ''​%%;​%%''​.
 +
 +Observăm exemplul de mai jos:
 +
 +<code bash>
 +student@uso:​~$ find workspace/C -type f -name "​*search*"​ -exec ls -l {} \;
 +-rw-r--r-- 1 student student 3312 sep 17 19:20 workspace/​C/​searching/​modified_binary_search.c
 +-rw-r--r-- 1 student student 1782 sep 17 19:20 workspace/​C/​searching/​ternary_search.c
 +-rw-r--r-- 1 student student 1624 sep 17 19:20 workspace/​C/​searching/​jump_search.c
 +-rw-r--r-- 1 student student 2799 sep 17 19:20 workspace/​C/​searching/​binary_search.c
 +-rw-r--r-- 1 student student 867 sep 17 19:20 workspace/​C/​searching/​other_binary_search.c
 +</​code>​
 +În exemplul de mai sus, argumetul opțiunii ''​%%exec%%''​ este ''​%%ls -l {} \;​%%''​. În cuvinte, pentru fiecare fișier text care conține șirul **search** vom afișa informații în format lung (''​%%ls -l {}%%''​). Observăm că ''​%%-exec%%''​ se încheie cu ''​%%\;​%%'':​ este nevoie să escapăm caracterul ''​%%;​%%''​ pentru ca acesta să fie interpretat de către utilitarul ''​%%find%%''​ și nu de către terminalul în care rulăm, exact ca în cazul ''​%%-name PATTERN%%''​.
 +
 +În secțiunile ce urmează vom vedea cum ne folosim de opțiunea ''​%%exec%%''​ pentru a face recursiv search & replace în fișiere.
 +
 +=== Exerciții ===
 +
 +  - Folosind ''​%%find%%''​ căutați fișierele care conțin șirul ''​%%bubble_sort%%''​ în nume.
 +  - Folosind ''​%%find%%''​ căutați fișierele care conțin șirul ''​%%quick_sort%%''​ în nume.
 +  - Folosind ''​%%find%%''​ căutați fișierele care conțin șirul ''​%%merge_sort%%''​ în nume.
 +  - Folosind ''​%%find%%''​ căutați fișierele care conțin șirul ''​%%sort%%''​ în nume.
 +
 +
 +===== Inspectarea rapida a conținutului fișierelor =====
 +
 +În secțiunea anterioară,​ ''​Inspectarea sistemului de fișiere'',​ am văzut cum căutăm fișiere în sistem cu ajutorul utilitarelor ''​%%locate%%''​ și ''​%%find%%''​. Căutăm un fișier cu un scop: vrem să găsim fișierul ''​%%README%%''​ pentru informații despre compilarea proiectului,​ vrem să ne amintim un detaliu de implementare din cod, etc.
 +
 +De cele mai multe ori acțiunea noastră se poate grupa în una din următoarele două categorii:
 +
 +  * Ne dorim să inspectăm rapid conținutul fișierelor pentru a ne da seama dacă am găsit informația căutată.
 +  * Ne dorim să afișăm pe ecran conținutul fișierelor pentru a extrage și prelucra informații din acestea.
 +
 +==== Căutarea informației într-un fișier ====
 +
 +Pentru a vedea rapid conținutul unui fișier folosim utlitarul ''​%%less%%''​.
 +
 +<​note>​
 +
 +
 +De fapt, comanda ''​%%man%%''​ folosește utilitarul ''​%%less%%''​ pentru a afișa paginile de manual. ''​%%less%%''​ este pagerul implicit în majoritatea distribuțiilor Linux.
 +</​note>​
 +
 +Avem fișierul ''​%%workspace/​C/​searching/​binary_search.c%%''​. Vrem să ne facem rapid o idee despre cum arată implementarea algoritmului **binary_search**. Inspectăm conținutul fișierului ''​%%workspace/​C/​searching/​binary_search.c%%'',​ folosind utilitarul ''​%%less%%'',​ ca în exemplul de mai jos:
 +
 +<code bash>
 +student@uso:​~$ less workspace/​C/​searching/​binary_search.c
 +
 +/**
 + * @file
 + * @brief Program to perform [binary
 + * search](https://​en.wikipedia.org/​wiki/​Binary_search_algorithm) of a target
 + * value in a given *sorted* array.
 + * @authors [James McDermott](https://​github.com/​theycallmemac) - recursive
 + * algorithm
 + * @authors [Krishna Vedala](https://​github.com/​kvedala) - iterative algorithm
 + */
 +#include <​assert.h>​
 +#include <​stdio.h>​
 +
 +/** Recursive implementation
 + * \param[in] arr array to search
 + * \param l left index of search range
 + * \param r right index of search range
 + * \param x target value to search for
 + * \returns location of x assuming array arr[l..r] is present
 + * \returns -1 otherwise
 + */
 +int binarysearch1(const int *arr, int l, int r, int x)
 +{
 +    if (r >= l)
 +    {
 +        int mid = l + (r - l) / 2;
 +
 +        // If element is present at middle
 +        if (arr[mid] == x)
 +            return mid;
 +
 +</​code>​
 +Observăm că acum avem o sesiune interactivă în interiorul căreia putem explora fișierul.
 +
 +<​note>​
 +
 +
 +În cadrul unei sesiuni ''​%%less%%''​ putem folosi aceeleași taste ca în cadrul sesiunii interactive ''​%%man%%''​ pentru navigarea în pagină:
 +
 +  * ''​%%Ctrl+n%%''/''​%%Ctrl+p%%''​ sau ''​%%j%%''/''​%%k%%''​ pentru a naviga, cu câte o linie, în jos, respectiv în sus; recomandăm utlizarea tastelor ''​%%j%%''/''​%%k%%''​ pentru a fi mai eficienți
 +  * ''​%%Ctrl+f%%''/''​%%Ctrl+b%%''​ pentru a naviga, cu câte o pagină de terminal, în jos, respectiv în sus
 +  * Search (''​%%/​%%'',​ ''​%%?​%%'',​ ''​%%n%%'',​ ''​%%N%%''​)
 +  * Go up (''​%%g%%''​),​ go down (''​%%G%%''​)
 +  * Help (''​%%h%%''​) pentru a afla mai multe despre cum putem folosi mai bine sesiunea interactivă
 +  * Quit (''​%%q%%''​) pentru a ieși din sesiunea interactivă
 +
 +Toate aceste informații se găsesc în pagina de manual a utilitarului ''​%%less%%'':​ ''​%%man less%%''​.
 +</​note>​
 +
 +În sesiunea interactivă căutăm după cuvântul cheie **search**. Pentru a porni căutarea apăsăm tasta ''​%%/​%%'',​ introducem textul căutat (**search**) și apăsăm tasta ''​%%Enter%%''​. Apăsăm tasta ''​%%n%%''​ pentru a merge la următoarea apariție a textului căutat; apăsăm ''​%%n%%''​ până când ajungem la implementarea funcției ''​%%binarysearch2%%''​.
 +
 +=== Exerciții ===
 +
 +  - Analizați, folosind ''​%%less%%'',​ algoritmul de căutare din fișierul ''​%%workspace/​C/​searching/​linear_search.c%%''​. Ce implementare este mai eficientă: **binary_search** sau **linear_search**?​
 +  - Analizați, folosind ''​%%less%%'',​ algoritmul de sortare **quick_sort**. Folosiți utilitarul ''​%%find%%''​ pentru a găsi fișierul sursă care conține implementarea.
 +  - Analizați, folosind ''​%%less%%'',​ algoritmul de sortare **merge_sort**. Folosiți utilitarul ''​%%find%%''​ pentru a găsi fișierul sursă care conține implementarea.
 +  - Căutați pe Google detalii despre cei doi algoritmi de sortare și încercați să vă răspundeți la întrebarea:​ Când folosim **merge_sort** și când folosim **quick_sort**?​
 +
 +==== Prelucrarea informației dintr-un fișier ====
 +
 +Pentru a afișa pe ecran conținutul unui fișier folosim utlitarul ''​%%cat%%''​. Rulăm comanda de mai jos, pentru a exemplifica:​
 +
 +<code bash>
 +student@uso:​~$ cat workspace/​C/​searching/​binary_search.c
 +/**
 + * @file
 + * @brief Program to perform [binary
 + * search](https://​en.wikipedia.org/​wiki/​Binary_search_algorithm) of a target
 + * value in a given *sorted* array.
 + * @authors [James McDermott](https://​github.com/​theycallmemac) - recursive
 + * algorithm
 + * @authors [Krishna Vedala](https://​github.com/​kvedala) - iterative algorithm
 + */
 +#include <​assert.h>​
 +#include <​stdio.h>​
 +
 +[...]
 +</​code>​
 +Observăm că pentru un fișier cu un număr mare de linii, așa cum este **binary_search.c**,​ afișarea întregului conținut pe ecran devine un impediment în a putea înțelege și urmări conținutul. De aceea vă încurajăm să folosiți ''​%%less%%''​ în loc de ''​%%cat%%''​ pentru a inspecta un fișier: vă este mult mai ușor să vă plimbați în interiorul fișierului și puteți folosi funcția search pentru a căuta în fișier. De asemeni, folosind ''​%%less%%''​ vă păstrați consola curată și puteți urmări mai ușor ce comenzi ați dat anterior și care au fost rezultatele acestora.
 +
 +Folosim comanda ''​%%cat%%''​ în combinație cu alte comenzi pentru a extrage sau filtra conținutul anumitor fișiere. Comanda ''​%%cat%%''​ primește ca argumente calea către unul sau mai multe fișiere și afișează pe ecran conținutul concatenat al acestora.
 +
 +Un exemplu uzual este faptul că vrem să extragem informațiile despre starea memoriei sistemului din fișierul ''​%%/​proc/​meminfo%%''​. Pentru aceasta rulăm comanda de mai jos:
 +
 +<code bash>
 +student@uso:​~$ cat /​proc/​meminfo | grep "​Mem"​
 +MemTotal: ​       2041248 kB
 +MemFree: ​         236092 kB
 +MemAvailable: ​    ​874420 kB
 +</​code>​
 +În exemplul de mai sus folosim ''​%%cat%%''​ pentru a oferi ca intrare conținutul fișierului ''​%%/​proc/​meminfo%%''​ utilitarului ''​%%grep%%'';​ cu utilitarul ''​%%grep%%''​ filtrăm conținutul după textul ''​%%"​Mem"​%%''​. Cu alte cuvinte, outputul comenzii ''​%%cat /​proc/​meminfo%%'',​ adică conținutul fișierului ''​%%/​proc/​meminfo%%''​ este textul pe care utilitarul ''​%%grep%%''​ îl prelucrează.
 +
 +**Exercițiu**:​ Plecând de la exemplul de mai sus, extrageți din fișierul ''​%%/​proc/​cpuinfo%%''​ dimensiunea memoriei cache a procesorului vostru; filtrați conținutul după textul ''​%%"​cache"​%%''​.
 +
 +=== Afișarea parțială a unui fișier ===
 +
 +Am văzut că utilitarul ''​%%cat%%''​ afișează întreg conținutul unui fișier. Există scenarii în care suntem interesați doar de începutul sau sfârșitul unui conținut. Pentru aceste cazuri putem folosi utilitarele:​
 +
 +  * ''​%%head%%''​ - afișează primele **10** linii din conținut
 +  * ''​%%tail%%''​ - afișează ultimele **10** linii din conținut
 +
 +<​note>​
 +
 +
 +Valoarea **10** este valoarea implicită a ambelor utilitare, dar putem specifica un alt număr de linii.
 +</​note>​
 +
 +Așa cum am observat în capitolul despre procese, putem folosi utilitarul ''​%%ps%%''​ pentru a vedea care sunt procesele din sistem și ce resurse consumă acestea. Memoria sistemului este una dintre cele mai importante resurse; dacă sistemul nostru rămâne fără memorie disponibilă,​ tot sistemul este afectat: sistemul se va "​mișca"​ mai greu, procesele se vor "​mișca"​ mai greu sau pot chiar să își întrerupă activitatea. Știind acest lucru, suntem interesați să vedem care sunt primele zece procese care consumă cea mai multă memorie.
 +
 +Folosim utilitarul ''​%%ps%%''​ pentru a afișa toate procesele din sistem:
 +
 +<code bash>
 +student@uso:​~$ ps -e -ouser,​uid,​pid,​%mem,​%cpu,​rss,​cmd --sort=%mem
 +
 +USER       ​UID ​  PID %MEM %CPU   RSS CMD
 +root         ​0 ​    ​2 ​ 0.0  0.0     0 [kthreadd]
 +
 +[...]
 +
 +student ​  ​1000 ​ 8338  3.0  0.0 61860 /​usr/​lib/​evolution/​evolution-calendar-factory-subprocess --factory all --bus-name org.gnome.evolution.dataserver.Subprocess.Backend.Calendarx8307x2 --own-path /​org/​gnome/​evolution/​dataserver/​Subprocess/​Backend/​Calendar/​8307/​2
 +student ​  ​1000 ​ 8307  3.1  0.0 64628 /​usr/​lib/​evolution/​evolution-calendar-factory
 +root         ​0 ​ 1338  3.8  0.0 78880 /​usr/​bin/​dockerd -H fd:// --containerd=/​run/​containerd/​containerd.sock
 +student ​  ​1000 ​ 7782  3.9  0.0 81312 /​usr/​lib/​xorg/​Xorg vt1 -displayfd 3 -auth /​run/​user/​1000/​gdm/​Xauthority -background none -noreset -keeptty -verbose 3
 +student ​  ​1000 ​ 8437  8.4  0.0 171916 /​usr/​bin/​gnome-software --gapplication-service
 +student ​  ​1000 ​ 7938 18.0  0.1 368304 /​usr/​bin/​gnome-shell
 +</​code>​
 +Am folosit opțiunea ''​%%-ouser,​uid,​pid,​%mem,​%cpu,​rss,​cmd%%''​ pentru a selecta coloanele pe care să le afișeze ''​%%ps%%''​.
 +
 +Am folosit opțiunea ''​%%--sort%%''​ cu argumentul ''​%%%mem%%''​ pentru a sorta procesele după procentul de memorie folosită.
 +
 +<​note>​
 +
 +
 +Folosiți comanda ''​%%ps -e -ouser,​uid,​pid,​%mem,​%cpu,​rss,​cmd --sort=%mem | less%%''​ pentru a vizualiza rezultatul comenzii ''​%%ps%%''​ într-o sesiune interactivă ''​%%less%%''​.
 +</​note>​
 +
 +Observăm că avem procesele sortate crescător după coloana ''​%%%MEM%%''​. Folosim utilitarul ''​%%tail%%''​ pentru a extrage din rezultatul ''​%%ps%%''​ cele mai consumatoare zece procese:
 +
 +<code bash>
 +student@uso:​~$ ps -e -ouser,​uid,​pid,​%mem,​%cpu,​rss,​cmd --sort=%mem | tail
 +student ​  1000 12966  1.8  0.0 38216 /​usr/​lib/​gnome-terminal/​gnome-terminal-server
 +root         ​0 ​ 1074  2.2  0.0 45460 /​usr/​bin/​containerd
 +student ​  ​1000 ​ 8274  2.3  0.0 48296 nautilus-desktop
 +root         ​0 ​  ​336 ​ 2.6  0.0 53612 /​lib/​systemd/​systemd-journald
 +student ​  ​1000 ​ 8338  3.0  0.0 61860 /​usr/​lib/​evolution/​evolution-calendar-factory-subprocess --factory all --bus-name org.gnome.evolution.dataserver.Subprocess.Backend.Calendarx8307x2 --own-path /​org/​gnome/​evolution/​dataserver/​Subprocess/​Backend/​Calendar/​8307/​2
 +student ​  ​1000 ​ 8307  3.1  0.0 64628 /​usr/​lib/​evolution/​evolution-calendar-factory
 +root         ​0 ​ 1338  3.8  0.0 78880 /​usr/​bin/​dockerd -H fd:// --containerd=/​run/​containerd/​containerd.sock
 +student ​  ​1000 ​ 7782  3.9  0.0 81312 /​usr/​lib/​xorg/​Xorg vt1 -displayfd 3 -auth /​run/​user/​1000/​gdm/​Xauthority -background none -noreset -keeptty -verbose 3
 +student ​  ​1000 ​ 8437  8.4  0.0 171916 /​usr/​bin/​gnome-software --gapplication-service
 +student ​  ​1000 ​ 7938 18.0  0.1 368248 /​usr/​bin/​gnome-shell
 +</​code>​
 +În acest moment am găsit răspunsul căutat, dar avem două mici neajunsuri:
 +
 +  * Ne lipsește antetul, așa că nu știm ce informații avem pe coloane
 +  * Procesele sunt sortate crescător, a.î. cel mai consumator este ultimul; vrem să fie sortate descrescător
 +
 +Rezolvăm cele două probleme prin intermediul opțiunii ''​%%--sort%%'':​ dacă punem un ''​%%-%%''​ (minus) în fața argumentului după care sortăm, o să sortăm descrescător. Rulăm comanda:
 +
 +<code bash>
 +student@uso:​~$ ps -e -ouser,​uid,​pid,​%mem,​%cpu,​rss,​cmd --sort=-%mem | less
 +USER       ​UID ​  PID %MEM %CPU   RSS CMD
 +student ​  ​1000 ​ 7938 18.0  0.1 368248 /​usr/​bin/​gnome-shell
 +student ​  ​1000 ​ 8437  8.4  0.0 171916 /​usr/​bin/​gnome-software --gapplication-service
 +student ​  ​1000 ​ 7782  3.9  0.0 81312 /​usr/​lib/​xorg/​Xorg vt1 -displayfd 3 -auth /​run/​user/​1000/​gdm/​Xauthority -background none -noreset -keeptty -verbose 3
 +root         ​0 ​ 1338  3.8  0.0 78880 /​usr/​bin/​dockerd -H fd:// --containerd=/​run/​containerd/​containerd.sock
 +student ​  ​1000 ​ 8307  3.1  0.0 64628 /​usr/​lib/​evolution/​evolution-calendar-factory
 +
 +[...]
 +</​code>​
 +Observăm că acum avem formatul dorit. Ne mai rămâne să extragem primele **11** linii din rezultatul comenzii de mai sus; **11** deoarece prima este linia antetului iar următoarele zece sunt procesele de interes. Pentru aceasta utilizăm comanda ''​%%head%%''​ cu opțiunea ''​%%-11%%''​ ca în exemplul de mai jos:
 +
 +<code bash>
 +student@uso:​~$ ps -e -ouser,​uid,​pid,​%mem,​%cpu,​rss,​cmd --sort=-%mem | head -11
 +USER       ​UID ​  PID %MEM %CPU   RSS CMD
 +student ​  ​1000 ​ 7938 18.0  0.1 367952 /​usr/​bin/​gnome-shell
 +student ​  ​1000 ​ 8437  8.4  0.0 171916 /​usr/​bin/​gnome-software --gapplication-service
 +student ​  ​1000 ​ 7782  3.9  0.0 81312 /​usr/​lib/​xorg/​Xorg vt1 -displayfd 3 -auth /​run/​user/​1000/​gdm/​Xauthority -background none -noreset -keeptty -verbose 3
 +root         ​0 ​ 1338  3.8  0.0 78880 /​usr/​bin/​dockerd -H fd:// --containerd=/​run/​containerd/​containerd.sock
 +student ​  ​1000 ​ 8307  3.1  0.0 64628 /​usr/​lib/​evolution/​evolution-calendar-factory
 +student ​  ​1000 ​ 8338  3.0  0.0 61860 /​usr/​lib/​evolution/​evolution-calendar-factory-subprocess --factory all --bus-name org.gnome.evolution.dataserver.Subprocess.Backend.Calendarx8307x2 --own-path /​org/​gnome/​evolution/​dataserver/​Subprocess/​Backend/​Calendar/​8307/​2
 +root         ​0 ​  ​336 ​ 2.6  0.0 53612 /​lib/​systemd/​systemd-journald
 +student ​  ​1000 ​ 8274  2.3  0.0 48296 nautilus-desktop
 +root         ​0 ​ 1074  2.2  0.0 45460 /​usr/​bin/​containerd
 +student ​  1000 12966  1.8  0.0 38216 /​usr/​lib/​gnome-terminal/​gnome-terminal-server
 +</​code>​
 +=== Exerciții ===
 +
 +  - Afișați primele zece procese sortate în funcție de memoria ocupată (Hint: RSS). Nu uitați să includeți antetul.
 +  - Afișați ultimele zece procese sortate în funcție de utilizarea procesorului (Hint: CPU). Nu uitați să includeți antetul.
 +
 +===== Căutarea în fișiere =====
 +
 +Așa cum am văzut până în acest punct din carte, majoritatea comenzilor Linux afișează o gamă largă de informații pe care apoi utilizatorul (adică noi) le filtrează pentru a extrage ceea ce îl intresează. La începutul acestei secțiuni, dar și de-a lungul cărții, am folosit utilitarul ''​%%grep%%''​ ca să filtrăm rezultatul unei comenzi.
 +
 +Comanda ''​%%grep%%''​ este una dintre cele mai folosite în linie de comandă. Sintaxa de folosire a ''​%%grep%%''​ este următoarea:​
 +
 +<code bash>
 +SYNOPSIS
 +       grep [OPTIONS] PATTERN [FILE...]
 +</​code>​
 +''​%%grep%%''​ caută **PATTERN** în lista de fișiere primită ca argument și afișează liniile care conțin **PATTERN**-ul căutat. Atunci când nu primește nici un fișier, citește text de la tastatură (intrarea standard) și afișează liniile care conțin **PATTERN**-ul căutat.
 +
 +Până acum noi am utilizat ''​%%grep%%''​ după modelul de mai jos:
 +
 +<code bash>
 +student@uso:​~$ cat workspace/​C/​searching/​binary_search.c | grep search
 + * search](https://​en.wikipedia.org/​wiki/​Binary_search_algorithm) of a target
 + * \param[in] arr array to search
 + * \param l left index of search range
 + * \param r right index of search range
 + * \param x target value to search for
 +int binarysearch1(const int *arr, int l, int r, int x)
 +
 +[...]
 +</​code>​
 +În exemplul de mai sus, operatorul ''​%%|%%''​ trimite textul afișat de comanda ''​%%cat%%''​ către intrarea standard a comenzii ''​%%grep%%''​. Vom discuta mai multe despre acesta în secțiunea ''​%%improve_cli_improve_shell_oneliners%%''​.
 +
 +Comanda următoare este echivalentă cu cea de mai sus:
 +
 +<code bash>
 +student@uso:​~$ grep search workspace/​C/​searching/​binary_search.c
 + * search](https://​en.wikipedia.org/​wiki/​Binary_search_algorithm) of a target
 + * \param[in] arr array to search
 + * \param l left index of search range
 + * \param r right index of search range
 + * \param x target value to search for
 +int binarysearch1(const int *arr, int l, int r, int x)
 +[...]
 +</​code>​
 +Observăm modul de folosire: ''​%%grep PATTERN cale/​către/​fișier%%''​.
 +
 +==== Exerciții ====
 +
 +  - Căutați //​patternul//​ "​l"​ în fișierul ''​%%binary_search.c%%'',​ pentru a vedea unde este folosit parametrul **left**. Observați cât de multe rezultate irelevante ați găsit datorită faptului că am căutat doar caracterul **l**. Aici există o lecție de învățat. Numele variabilelor sunt foarte improtante: nu fac doar codul mai ușor de înțeles, dar ajută și căutarea. Folosiți //​patternul//​ "param l" în încercarea de a restrânge căutarea.
 +  - Căutați //​patternul//​ "​arr"​ în fișierul ''​%%binary_search.c%%''​.
 +  - Căutați //​patternul//​ "​binarysearch1"​ în fișierul ''​%%binary_search.c%%''​ pentru a vedea cum este apelată funcția de căutare.
 +
 +==== Opțiuni uzuale ale grep ====
 +
 +=== Afișarea numărului liniei care conține patternul ===
 +
 +Folosim opțiunea ''​%%-n%%''​ pentru a afișa și numărul liniei care conține patternul căutat:
 +
 +<code bash>
 +student@uso:​~$ grep -n search workspace/​C/​searching/​binary_search.c
 +4: * search](https://​en.wikipedia.org/​wiki/​Binary_search_algorithm) of a target
 +14: * \param[in] arr array to search
 +15: * \param l left index of search range
 +16: * \param r right index of search range
 +17: * \param x target value to search for
 +21:int binarysearch1(const int *arr, int l, int r, int x)
 +[...]
 +</​code>​
 +=== Căutarea case-insensitive ===
 +
 +Implicit, grep caută în mod case-sensitive patternul, așa cum putem observa din exemplul de mai jos:
 +
 +<code bash>
 +student@uso:​~$ grep Search workspace/​C/​searching/​binary_search.c
 +</​code>​
 +Pentru a efectua căutarea textului în mod case-insesnsitive,​ folosim opțiunea ''​%%-i%%'',​ ca în exemplul de mai jos:
 +
 +<code bash>
 +student@uso:​~$ grep -i Search workspace/​C/​searching/​binary_search.c
 + * search](https://​en.wikipedia.org/​wiki/​Binary_search_algorithm) of a target
 + * \param[in] arr array to search
 + * \param l left index of search range
 + * \param r right index of search range
 + * \param x target value to search for
 +int binarysearch1(const int *arr, int l, int r, int x)
 +[...]
 +</​code>​
 +=== Excluderea unui pattern ===
 +
 +Pentru a afișa toate liniile, mai puțin pe cele care conțin pattern, folosim opțiunea ''​%%-v%%'',​ ca în exemplul de mai jos:
 +
 +<code bash>
 +student@uso:​~$ grep -v search workspace/​C/​searching/​binary_search.c | less
 +/**
 + * @file
 + * @brief Program to perform [binary
 + * value in a given *sorted* array.
 + * @authors [James McDermott](https://​github.com/​theycallmemac) - recursive
 + * algorithm
 + * @authors [Krishna Vedala](https://​github.com/​kvedala) - iterative algorithm
 + */
 +#include <​assert.h>​
 +#include <​stdio.h>​
 +[...]
 +</​code>​
 +=== Căutarea recursivă a unui pattern ===
 +
 +În căutările noastre de până acum, ca și în exemplele de mai sus, am presupus că știm în ce fișiere se găsește informația căutată de noi. Acest lucru este adevărat pentru fișiere din sistem cu informații bine cunoscute, cum ar fi ''​%%/​proc/​meminfo%%'',​ dar atunci când lucrăm cu un proiect nou nu vom ști în ce fișiere să căutăm informația dorită. De exemplu, în cazul proiectului cu algoritmi implementați în C, noi am făcut presupunerea că vom găsi linii care conțin patternul **search** în fișierul ''​%%workspace/​C/​searching/​binary_search.c%%''​.
 +
 +Atunci când nu știm în ce fișiere se află informația căutată putem să-i spunem lui ''​%%grep%%''​ să caute recursiv prin toată ierarhia de fișiere dintr-un anumit director. Pentru a efectua o căutare recursivă folosim opțiunea ''​%%-r%%'',​ ca în exemplul de mai jos:
 +
 +<code bash>
 +student@uso:​~$ grep -r search workspace/​C/​ | less
 +
 +workspace/​C/​leetcode/​src/​700.c:​struct TreeNode *searchBST(struct TreeNode *root, int val)
 +workspace/​C/​leetcode/​src/​700.c: ​       return searchBST(root->​left,​ val);
 +workspace/​C/​leetcode/​src/​700.c: ​       return searchBST(root->​right,​ val);
 +workspace/​C/​leetcode/​src/​35.c:​int searchInsert(int *nums, int numsSize, int target)
 +workspace/​C/​leetcode/​src/​35.c:​int searchInsert(int *nums, int numsSize, int target)
 +workspace/​C/​leetcode/​src/​35.c: ​       return searchInsert(nums,​ numsSize - 1, target);
 +workspace/​C/​leetcode/​src/​704.c:​int search(int *nums, int numsSize, int target)
 +workspace/​C/​leetcode/​src/​704.c:/​* Another solution: Using bsearch() */
 +workspace/​C/​leetcode/​src/​704.c:​int search(int *nums, int numsSize, int target)
 +workspace/​C/​leetcode/​src/​704.c: ​   int *ret = bsearch(&​target,​ nums, numsSize, sizeof(int),​ cmpint);
 +workspace/​C/​leetcode/​README.md:​|35|[Search Insert Position](https://​leetcode.com/​problems/​search-insert-position/​) | [C](./​src/​35.c)|Easy|
 +workspace/​C/​leetcode/​README.md:​|108|[Convert Sorted Array to Binary Search Tree](https://​leetcode.com/​problems/​convert-sorted-array-to-binary-search-tree/​) | [C](./​src/​108.c)|Easy|
 +workspace/​C/​leetcode/​README.md:​|109|[Convert Sorted List to Binary Search Tree](https://​leetcode.com/​problems/​convert-sorted-list-to-binary-search-tree/​) | [C](./​src/​109.c)|Medium|
 +workspace/​C/​leetcode/​README.md:​|173|[Binary Search Tree Iterator](https://​leetcode.com/​problems/​binary-search-tree-iterator/​) | [C](./​src/​173.c)|Medium|
 +workspace/​C/​leetcode/​README.md:​|700|[Search in a Binary Search Tree](https://​leetcode.com/​problems/​search-in-a-binary-search-tree/​) | [C](./​src/​700.c)|Easy|
 +workspace/​C/​leetcode/​README.md:​|701|[Insert into a Binary Search Tree](https://​leetcode.com/​problems/​insert-into-a-binary-search-tree/​) | [C](./​src/​701.c)|Medium|
 +workspace/​C/​leetcode/​README.md:​|704|[Binary Search](https://​leetcode.com/​problems/​binary-search/​) | [C](./​src/​704.c)|Easy|
 +workspace/​C/​DIRECTORY.md: ​   * [Binary Search Tree](https://​github.com/​TheAlgorithms/​C/​blob/​master/​data_structures/​binary_trees/​binary_search_tree.c)
 +workspace/​C/​DIRECTORY.md: ​ * [Binary Search](https://​github.com/​TheAlgorithms/​C/​blob/​master/​searching/​binary_search.c)
 +workspace/​C/​DIRECTORY.md: ​ * [Fibonacci Search](https://​github.com/​TheAlgorithms/​C/​blob/​master/​searching/​fibonacci_search.c)
 +</​code>​
 +=== Best practice ===
 +
 +De cele mai multe ori vom folosi opțiunile ''​%%-n%%'',​ ''​%%-i%%''​ și ''​%%-r%%''​ în aceelași timp. În cazul nostru de până acum, aceasta se traduce în:
 +
 +<code bash>
 +student@uso:​~$ grep -nri search workspace/​C/​ | less
 +
 +workspace/​C/​leetcode/​src/​700.c:​10:​struct TreeNode *searchBST(struct TreeNode *root, int val)
 +workspace/​C/​leetcode/​src/​700.c:​21: ​       return searchBST(root->​left,​ val);
 +workspace/​C/​leetcode/​src/​700.c:​25: ​       return searchBST(root->​right,​ val);
 +workspace/​C/​leetcode/​src/​35.c:​1:​int searchInsert(int *nums, int numsSize, int target)
 +workspace/​C/​leetcode/​src/​35.c:​18:​int searchInsert(int *nums, int numsSize, int target)
 +workspace/​C/​leetcode/​src/​35.c:​27: ​       return searchInsert(nums,​ numsSize - 1, target);
 +workspace/​C/​leetcode/​src/​704.c:​1:​int search(int *nums, int numsSize, int target)
 +workspace/​C/​leetcode/​src/​704.c:​23:/​* Another solution: Using bsearch() */
 +workspace/​C/​leetcode/​src/​704.c:​26:​int search(int *nums, int numsSize, int target)
 +workspace/​C/​leetcode/​src/​704.c:​28: ​   int *ret = bsearch(&​target,​ nums, numsSize, sizeof(int),​ cmpint);
 +workspace/​C/​leetcode/​README.md:​26:​|35|[Search Insert Position](https://​leetcode.com/​problems/​search-insert-position/​) | [C](./​src/​35.c)|Easy|
 +workspace/​C/​leetcode/​README.md:​35:​|108|[Convert Sorted Array to Binary Search Tree](https://​leetcode.com/​problems/​convert-sorted-array-to-binary-search-tree/​) | [C](./​src/​108.c)|Easy|
 +workspace/​C/​leetcode/​README.md:​36:​|109|[Convert Sorted List to Binary Search Tree](https://​leetcode.com/​problems/​convert-sorted-list-to-binary-search-tree/​) | [C](./​src/​109.c)|Medium|
 +workspace/​C/​leetcode/​README.md:​47:​|173|[Binary Search Tree Iterator](https://​leetcode.com/​problems/​binary-search-tree-iterator/​) | [C](./​src/​173.c)|Medium|
 +workspace/​C/​leetcode/​README.md:​78:​|700|[Search in a Binary Search Tree](https://​leetcode.com/​problems/​search-in-a-binary-search-tree/​) | [C](./​src/​700.c)|Easy|
 +workspace/​C/​leetcode/​README.md:​79:​|701|[Insert into a Binary Search Tree](https://​leetcode.com/​problems/​insert-into-a-binary-search-tree/​) | [C](./​src/​701.c)|Medium|
 +workspace/​C/​leetcode/​README.md:​80:​|704|[Binary Search](https://​leetcode.com/​problems/​binary-search/​) | [C](./​src/​704.c)|Easy|
 +workspace/​C/​.github/​pull_request_template.md:​20:​- [ ] Search previous suggestions before making a new one, as yours may be a duplicate.
 +workspace/​C/​DIRECTORY.md:​31: ​   * [Binary Search Tree](https://​github.com/​TheAlgorithms/​C/​blob/​master/​data_structures/​binary_trees/​binary_search_tree.c)
 +workspace/​C/​DIRECTORY.md:​338:##​ Searching
 +:
 +</​code>​
 +Astfel avem o căutare cât mai cuprinzătoare și putem folosi funcția de căutare în sesiunea interactivă ''​%%less%%''​ pentru a găsi linia și fișierul care ne interesează.
 +
 +=== Căutarea unui cuvânt ===
 +
 +Din rezultatele căutărilor de mai sus observăm că ''​%%grep%%''​ caută patternul dat ca un subșir. Acest lucru se vede foarte ușor în rezultatul anterior:
 +
 +<code bash>
 +student@uso:​~$ grep -nri search workspace/​C/​ | less
 +
 +workspace/​C/​leetcode/​src/​700.c:​10:​struct TreeNode *searchBST(struct TreeNode *root, int val)
 +</​code>​
 +Observăm că patternul **search** se regăsește în șirul ***searchBST**. Dacă dorim să căutăm cuvântul **search** folosim opțiunea ''​%%-w%%''​ (word) pentru a-i transmite utilitarului că patternul trebuie tratat ca un cuvânt, ca în exemplul de mai jos:
 +
 +<code bash>
 +student@uso:​~$ grep -nri -w "​search"​ workspace/​C/​ | less
 +
 +workspace/​C/​leetcode/​src/​704.c:​1:​int search(int *nums, int numsSize, int target)
 +workspace/​C/​leetcode/​src/​704.c:​26:​int search(int *nums, int numsSize, int target)
 +workspace/​C/​leetcode/​README.md:​26:​|35|[Search Insert Position](https://​leetcode.com/​problems/​search-insert-position/​) | [C](./​src/​35.c)|Easy|
 +[...]
 +</​code>​
 +Observăm că acum rezultatele conțin doar cuvântul **search**.
 +
 +=== Exerciții ===
 +
 +  - Găsiți toate fișierele care includ headerul ''​%%stdio.h%%''​.
 +  - Găsiți toate aparițiile patternului ''​%%binarySearch%%''​.
 +  - Găsiți toate aparițiile patternului ''​%%quickSort%%''​.
 +
 +====== O înțelegere mai bună a shellului ======
 +
 +===== Execuția comenzilor =====
 +
 +==== Încheierea execuției unei comenzi ====
 +
 +Atunci când rulăm o comandă aceasta își poate încheia execuția în două moduri: cu **succes** sau cu **eșec**. Atunci când își încheie execuția, orice proces întoarce un cod de eroare, care este un număr:
 +
 +  * Dacă numărul întors are valoarea ''​%%0%%'',​ procesul și-a încheiat execuția cu succes.
 +  * Dacă numărul întors are orice altă valoare, procesul și-a încheiat execuția cu eroare, iar codul întors poate fi folosit pentru a afla mai multe informații despre eroarea pe care a întors-o procesul. În pagina ''​%%man%%''​ a utilitarului ''​%%ls%%''​ este specificat:<​code bash>
 +Exit status:
 +       ​0 ​     if OK,
 +
 +       ​1 ​     if minor problems (e.g., cannot access subdirectory),​
 +
 +       ​2 ​     if serious trouble (e.g., cannot access command-line argument).
 +</​code>​
 +
 +Pentru a vedea codul cu care și-a încheiat execuția o comandă folosim sintaxa ''​%%$?​%%''​. Urmărim exemplul de mai jos:
 +
 +<code bash>
 +student@uso:​~$ ls Desktop/
 +todos.txt
 +student@uso:​~$ echo $?
 +0
 +student@uso:​~$ ls non-existent
 +ls: cannot access '​non-existent':​ No such file or directory
 +student@uso:​~$ echo $?
 +2
 +</​code>​
 +Observăm că în cazul fișierului inexistet, comanda ''​%%ls non-existent%%''​ a întors valoarea ''​%%2%%'',​ așa cum era specificat și în pagina de manual.
 +
 +=== Înlănțuirea comenzilor în funcție de succes sau eșec ===
 +
 +De multe ori vrem să executăm o succesiune de comenzi pentru a realiza o sarcină. De exemplu, atunci când vrem să instalăm o aplicație o rulăm trei comenzi:
 +
 +  * O să actualizăm indexul surselor de pachete folosind ''​%%apt update%%''​
 +  * O să instalăm pachetul care conține aplicația folosind ''​%%apt install%%''​
 +  * O să rulăm aplicația pentru a valida că instalarea a fost cu succes.
 +
 +Preferăm să înlănțuim cele trei comenzi într-una singură pentru că astfel putem să pornim tot acest proces, să plecăm de la calculator, iar când ne întoarcem avem tot sistemul pregătit.
 +
 +Pentru a înlănțui comenzi în terminalul bash avem trei operatori disponibili:​
 +
 +<​HTML><​ul></​HTML>​
 +<​HTML><​li></​HTML><​HTML><​p></​HTML>​Operatorul ''​%%;​%%''​ - este folosit pentru separarea comenzilor Urmăm exemplul de mai jos:<​HTML></​p></​HTML>​
 +<code bash>
 +student@uso:​~$ mkdir demo; cd demo; touch Hello; ls
 +Hello
 +</​code>​
 +<​HTML><​p></​HTML>​În exemplul de mai sus am creat directorul ''​%%demo%%'',​ am navigat în interiorul său, am creat fișierul ''​%%Hello%%''​ și am afișat conținutul directorului. Am făcut toate acestea înlănțuind comenzile ''​%%mkdir%%'',​ ''​%%cd%%'',​ ''​%%touch%%''​ și ''​%%ls%%''​ cu ajutorul operatorului ''​%%;​%%''​.<​HTML></​p></​HTML>​
 +<​HTML><​p></​HTML>​Operatorul ''​%%;​%%''​ este folosit pentru separarea comenzilor, dar nu ține cont dacă comenzile anterioare au fost executate cu succes sau nu. Urmăm exemplul de mai jos:<​HTML></​p></​HTML>​
 +<code bash>
 +student@uso:​~$ mkdir operators/​demo;​ cd operators/​demo
 +mkdir: cannot create directory ‘operators/​demo’:​ No such file or directory
 +-bash: cd: operators/​demo:​ No such file or directory
 +</​code>​
 +<​HTML><​p></​HTML>​În exemplul de mai sus, comanda ''​%%mkdir%%''​ a eșuat deoarece nu a găsit directorul ''​%%operators%%''​ în care să creeze directorul ''​%%demo%%''​. Cu toate acestea, operatorul ''​%%;​%%''​ doar separă comenzile între ele, așa că și comanda ''​%%cd operators/​demo%%''​ a fost executată, și și aceasta a eșuat deoarece nu există calea ''​%%operators/​demo%%''​.<​HTML></​p></​HTML>​
 +<​HTML><​p></​HTML>​Folosim operatorul ''​%%;​%%''​ pentru a înlănțui comenzi care sunt independente unele de altele, și deci execuția lor nu depinde de succesul unei comenzi precedente.<​HTML></​p></​HTML><​HTML></​li></​HTML>​
 +<​HTML><​li></​HTML><​HTML><​p></​HTML>​Operatorul binar ''​%%&&​%%''​ (și logic) - execută a doua comandă doar dacă precedenta s-a executat cu succes. Exemplul anterior devine:<​HTML></​p></​HTML>​
 +<code bash>
 +student@uso:​~$ mkdir operators/​demo && cd operators/​demo
 +mkdir: cannot create directory ‘operators/​demo’:​ No such file or directory
 +</​code>​
 +<​HTML><​p></​HTML>​Observăm că din moment ce comanda ''​%%mkdir%%''​ a eșuat, comanda ''​%%cd%%''​ nu a mai fost executată.<​HTML></​p></​HTML><​HTML></​li></​HTML>​
 +<​HTML><​li></​HTML><​HTML><​p></​HTML>​Operatorul binar ''​%%||%%''​ (sau logic) - execută a doua comandă doar dacă prima s-a terminat cu eșec. Urmărim exemplul de mai jos:<​HTML></​p></​HTML>​
 +<code bash>
 +student@uso:​~$ (ls -d operators || mkdir operators) && ls -d operators
 +ls: cannot access '​operators':​ No such file or directory
 +operators
 +student@uso:​~$ (ls -d operators || mkdir operators) && ls -d operators
 +operators
 +operators
 +</​code>​
 +<​HTML><​p></​HTML>​În exemplul de mai sus, prima comandă ''​%%ls%%''​ a eșuat, așa că a fost executată comanda ''​%%mkdir%%''​ și apoi a fost executată ultima comandă ''​%%ls%%''​. La cea de-a doua rulare, a fost executată cu succes prima comandă ''​%%ls%%'',​ așa că comanda ''​%%mkdir%%''​ nu a mai fost executată, și apoi a fost executată ultima comandă ''​%%ls%%''​.<​HTML></​p></​HTML><​HTML></​li></​HTML><​HTML></​ul></​HTML>​
 +
 +Pentru a rezolva scenariul de la care am plecat inițial, putem rula:
 +
 +<code bash>
 +sudo apt update && sudo apt install -y cowsay && cowsay "​Howdy"​
 +</​code>​
 +Comanda de mai sus va actualiza indexul pachetelor sursă, va instala pachetul ''​%%cowsay%%''​ și va rula comanda ''​%%cowsay%%''​ pentru a valida instalarea. O astfel de înlănțuire de comenzi este numită **oneliner**.
 +
 +=== Exerciții ===
 +
 +  - Scrieți un oneliner cu ajutorul căruia creați directorul ''​%%~/​uso-lab/​labs/​05-cli/​support/​make-folder%%''​ și apoi copiați conținutul directorului ~/​uso-lab/​labs/​05-cli/​support/​redir în el.
 +  - Actualizați onelinerul anterior astfel încât după copiere să pornească compilarea proiectului folosind comanda ''​%%make build%%''​.
 +
 +==== Înlănțuirea comenzilor folosind operatorul | (pipe) ====
 +
 +Așa cum am descoperit în secțiunile și capitolele anterioare, în mediul Linux avem multe utilitare care rezolvă o nevoie specifică: ''​%%ls%%''​ afișează informații despre fișiere, ''​%%ps%%''​ despre procese, ''​%%grep%%''​ filtrează, etc. Toate acestea au la bază filozofia mediului Linux: "do one thing and do it well". Ca întodeauna,​ frumusețea stă în simplitate: avem o suită de unelte la dispoziție,​ fiecare capabilă să rezolve rapid o sarcină dată; pentru a rezolva o problemă mai complexă trebuie doar să îmbinăm uneltele.
 +
 +Operatorul ''​%%|%%''​ (pipe) ne ajută să facem acest lucru. Atunci când folosim operatorul ''​%%|%%''​ preluăm rezultatul comenzii din stânga operatorului și îl oferim ca intrare comenzii aflate în dreapta operatorului.
 +
 +Am folosit de mai multe ori operatorul ''​%%|%%''​ până acum:
 +
 +  * Am afișat informații despre procesele din sistem și am filtrat după numele unui proces:<​code bash>
 +student@uso:​~$ ps -e | grep firefox
 +14912 pts/0    00:00:19 firefox
 +</​code>​
 +  * Am extras primele zece procese care consumă cel mai mare procent de memorie:<​code bash>
 +student@uso:​~$ ps -e -ouser,​uid,​pid,​%mem,​%cpu,​rss,​cmd --sort=-%mem | head -11
 +USER       ​UID ​  PID %MEM %CPU   RSS CMD
 +student ​  ​1000 ​ 7938 18.0  0.1 367952 /​usr/​bin/​gnome-shell
 +student ​  ​1000 ​ 8437  8.4  0.0 171916 /​usr/​bin/​gnome-software --gapplication-service
 +student ​  ​1000 ​ 7782  3.9  0.0 81312 /​usr/​lib/​xorg/​Xorg vt1 -displayfd 3 -auth /​run/​user/​1000/​gdm/​Xauthority -background none -noreset -keeptty -verbose 3
 +root         ​0 ​ 1338  3.8  0.0 78880 /​usr/​bin/​dockerd -H fd:// --containerd=/​run/​containerd/​containerd.sock
 +student ​  ​1000 ​ 8307  3.1  0.0 64628 /​usr/​lib/​evolution/​evolution-calendar-factory
 +student ​  ​1000 ​ 8338  3.0  0.0 61860 /​usr/​lib/​evolution/​evolution-calendar-factory-subprocess --factory all --bus-name org.gnome.evolution.dataserver.Subprocess.Backend.Calendarx8307x2 --own-path /​org/​gnome/​evolution/​dataserver/​Subprocess/​Backend/​Calendar/​8307/​2
 +root         ​0 ​  ​336 ​ 2.6  0.0 53612 /​lib/​systemd/​systemd-journald
 +student ​  ​1000 ​ 8274  2.3  0.0 48296 nautilus-desktop
 +root         ​0 ​ 1074  2.2  0.0 45460 /​usr/​bin/​containerd
 +student ​  1000 12966  1.8  0.0 38216 /​usr/​lib/​gnome-terminal/​gnome-terminal-server
 +</​code>​
 +
 +==== Alte exemple de prelucrări de text ====
 +
 +Ne amintim de fișierul ''/​etc/​passwd''​ conține informații despre toți utilizatorii din sistem. ​
 +
 +<code bash>
 +student@uso:​~$ cat /etc/passwd
 +root:​x:​0:​0:​root:/​root:/​bin/​bash
 +daemon:​x:​1:​1:​daemon:/​usr/​sbin:/​usr/​sbin/​nologin
 +bin:​x:​2:​2:​bin:/​bin:/​usr/​sbin/​nologin
 +(...)
 +</​code>​
 +
 +În Linux există filtrul de text ''​cut''​ prin care putem extrage doar anumite informații dintr-un output. ​
 +Să zicem că vrem să extragem doar numele utilizatorilor,​ fără informațiile legate de grupuri sau home directory.
 +
 +
 +<code bash>
 +student@uso:​~/​uso-lab$ cat /etc/passwd | cut -f1 -d":"​
 +root
 +daemon
 +bin
 +(...)
 +</​code>​
 +
 +
 +Argumentul ''​-f1''​ specifică faptul că vrem prima coloană, iar argumentul ''​-d:''​ specifică delimitatorul ​
 +de coloane, în cazul nostru '':''​.
 +
 +
 +  - Pornind de la comanda de mai sus, afișați numele utilizatorilor sortați alfabetic. (Hint: ''​man sort''​)
 +  - Folosind utilitarul ''​wc'',​ obțineți numărul de utilizatori din sistem. (Hint: ''​man wc''​)
 +  - Să afișeze cele mai consumatoare de memorie 10 procese din sistem. (Hint: folosiți ''​|''​ și ''​tail''​)
 +
 +
 +==== Redirectări ====
 +
 +Majoritatea utilitarelor pe care le folosim afișează rezultatele operațiilor pe care le aplică la ieșirea standard, adică pe ecran. În continuare vom aprofunda ceea ce am discutat despre redirectări în capitolul **Lucrul cu Fișiere**. Anterior am mai menționat și termenul de intrare standard; în această secțiune ne vom clarifica ce înseamnă, ce rol îndeplinesc și cum ne folosim de aceste cunoștințe.
 +
 +Orice proces folosește implicit trei fluxuri (streams) de date:
 +
 +  * **STDIN** - fluxul de intrare standard, referit și ca "citit de la tastatură"​. Spunem că un program care citește date de intrare din linie de comandă, deci așteaptă de la utilizator, citește de la intrarea standard; de aici și denumirea "citit de la tastatură"​. Complementul citirii de la tastatură este citirea datelor dintr-un fișier.
 +  * **STDOUT** - fluxul de ieșire standard, referit și ca "​afișare pe ecran"​. Spunem că un program afișează datele de ieșire pe ecran, adică scrie rezultatele procesărilor efectuate la ieșirea standard. Complementul afișării pe ecran este scrierea rezultatelor într-un fișier.
 +  * **STDERR** - fluxul de ieșire standard al erorilor. Un program corect scris o să scrie erorile în fluxul de ieșire al erorilor. Acest lucru permite filtrarea erorilor.
 +
 +În linie de comandă, atât STDOUT cât și STDERR vor apărea pe ecran. Datorită faptului că informațiile sunt scrise în două fluxuri distincte, utilizatorul are posibilitatea de a separa rezultatele de erori. Utilizatorul face aceasta folosind redirectări.
 +
 +=== Redirectarea ieșirilor standard ===
 +
 +Cum spuneam mai sus, majoritatea programelor pe care le folosim vor afișa rezultatele pe ecran. Acest comportament este bun atunci când ne scriem onelinerul care ne extrage informațiile căutate, dar cel mai probabil o să vrem să salvăm rezultatul procesării într-un fișier.
 +
 +Folosim operatorul ''​%%>​%%''​ pentru a redirecta **STDOUT** sau **STDERR** într-un fișier. Pentru fiecare flux de date avem un număr, numit descriptor de fișier, asociat:
 +
 +  * **STDIN** are asociat descriptorul de fișier 0
 +  * **STDOUT** are asociat descriptorul de fișier 1
 +  * **STDERR** are asociat descriptorul de fișier 2
 +
 +Pentru a redirecta ieșirea standard folosim sintaxa ''​%%cmd 1> nume-fișier%%''​. Pentru a redirecta ieșirea standard a erorilor folosim sintaxa ''​%%cmd 2> nume-fișier%%''​.
 +
 +<note warning>
 +
 +
 +**Atenție!** În cazul în care fișierul destinație nu există, operatorul ''​%%>​%%''​ îl va crea. Dacă fișierul destinație există, operatorul ''​%%>​%%''​ va șterge conținutul acestuia.
 +</​note>​
 +
 +Urmăm exemplul de mai jos:
 +
 +<code bash>
 +student@uso:​~$ ps -e -ouser,​uid,​pid,​%mem,​%cpu,​rss,​cmd --sort=-%mem | head -11
 +USER       ​UID ​  PID %MEM %CPU   RSS CMD
 +student ​  ​1000 ​ 7938 18.0  0.1 367952 /​usr/​bin/​gnome-shell
 +student ​  ​1000 ​ 8437  8.4  0.0 171916 /​usr/​bin/​gnome-software --gapplication-service
 +student ​  ​1000 ​ 7782  3.9  0.0 81312 /​usr/​lib/​xorg/​Xorg vt1 -displayfd 3 -auth /​run/​user/​1000/​gdm/​Xauthority -background none -noreset -keeptty -verbose 3
 +root         ​0 ​ 1338  3.8  0.0 78880 /​usr/​bin/​dockerd -H fd:// --containerd=/​run/​containerd/​containerd.sock
 +student ​  ​1000 ​ 8307  3.1  0.0 64628 /​usr/​lib/​evolution/​evolution-calendar-factory
 +student ​  ​1000 ​ 8338  3.0  0.0 61860 /​usr/​lib/​evolution/​evolution-calendar-factory-subprocess --factory all --bus-name org.gnome.evolution.dataserver.Subprocess.Backend.Calendarx8307x2 --own-path /​org/​gnome/​evolution/​dataserver/​Subprocess/​Backend/​Calendar/​8307/​2
 +root         ​0 ​  ​336 ​ 2.6  0.0 53612 /​lib/​systemd/​systemd-journald
 +student ​  ​1000 ​ 8274  2.3  0.0 48296 nautilus-desktop
 +root         ​0 ​ 1074  2.2  0.0 45460 /​usr/​bin/​containerd
 +student ​  1000 12966  1.8  0.0 38216 /​usr/​lib/​gnome-terminal/​gnome-terminal-server
 +student@uso:​~$ ps -e -ouser,​uid,​pid,​%mem,​%cpu,​rss,​cmd --sort=-%mem | head -11 1> top10-consumers
 +student@uso:​~$ less top10-consumers
 +</​code>​
 +Am scris, prin încercări succesive, onelinerul care ne afișează primele zece procese care consumă cea mai multă memorie. Apoi am folosit sintaxa ''​%%1>​ top10-consumers%%''​ pentru a redirecta rezultatul în fișierul **top10-consumers**.
 +
 +Urmăm exemplul de mai jos pentru a redirecta erorile:
 +
 +<code bash>
 +student@uso:​~$ ls D* F* > out 2> errs
 +student@uso:​~$ cat out
 +Desktop:
 +todos.txt
 +
 +Documents:
 +snippets.git
 +uni
 +uso.tar
 +
 +Downloads:
 +courses.tar
 +uso.tar
 +student@uso:​~$ cat errs
 +ls: cannot access '​F*':​ No such file or directory
 +</​code>​
 +Observăm că am folosit sintaxa ''​%%2>​ errs%%''​ pentru a redirecta erorile în fișierul **errs**. Observăm că pentru a redirecta ieșirea standard putem omite descriptorul de fișier, așa cum am făcut cu ''​%%>​ out%%''​.
 +
 +Atunci când rulăm o comandă, redirectăm erorile într-un fișier pentru că vrem să verificăm că totul s-a executat cu succes. De cele mai multe ori suntem în rumătorul scenariu:
 +
 +  - Urmează să executăm o comandă care durează mai mult timp și pentru care nu putem să ținem pasul, cu ochiul liber, cu fluxul de afișare a datelor pe ecran. Un exemplu este compilarea unui proiect mai mare.
 +  - O să pornim procesul și o să redirectăm STDOUT și STDERR în două fișiere, de ex. ''​%%out%%''​ și ''​%%err%%''​.
 +  - În timpul cât rulează noi putem să facem altceva: ne ocupăm de altă sarcină, ne facem o cafea, etc.
 +  - La finalul execuției inspectăm fișierele ''​%%out%%''​ și ''​%%err%%''​ pentru a vedea dacă au existat erori și le rezolvăm.
 +
 +<​note>​
 +
 +
 +Acum înțelegem cum funcționează operatorul ''​%%|%%''​ (pipe). Acesta conectează fluxul de ieșire (STDOUT) al comenzii din stânga sa cu fluxul de intrare (STDIN) al comenzii din dreapta.
 +</​note>​
 +
 +=== Redirectarea în mod append ===
 +
 +Implicit, operatoru ''​%%>​%%''​ șterge (trunchează) conținutul fișierului destinație. Dacă vrem să păstrăm conținutul fișierului și să adăugăm rezultatul redirectării în continuarea acestuia, folosim operatorul ''​%%>>​%%''​.
 +
 +Rulați din nou exemplele de mai sus folosind operatorul ''​%%>>​%%''​ în locul operatorului ''​%%>​%%''​. Folosiți less pentru a inspecta fișierele de ieșire și de erori.
 +
 +=== Fișiere speciale ===
 +
 +Pe sistemele Linux găsim un număr de fișiere speciale pe care le putem folosim în diferite scopuri:
 +
 +<​HTML><​ul></​HTML>​
 +<​HTML><​li></​HTML><​HTML><​p></​HTML>​Fișierul ''​%%/​dev/​null%%''​ este un fișier care ignoră orice este scris în el. Este echivalentul unei găuri negre în sistemul nostru. Cu ajutorul său, putem rescrie exemplul de mai sus în modul următor:<​HTML></​p></​HTML>​
 +<code bash>
 +student@uso:​~$ firefox &> /dev/null &
 +[1] 10349
 +student@uso:​~$ firefox > /dev/null 2>&1 &
 +[2] 10595
 +</​code>​
 +<​HTML><​p></​HTML>​Acum orice va genera ''​%%firefox%%''​ va fi scris în ''​%%/​dev/​null%%'',​ care va consuma textul primit fără a ocupa spațiu pe disc.<​HTML></​p></​HTML><​HTML></​li></​HTML>​
 +<​HTML><​li></​HTML><​HTML><​p></​HTML>​Fișierul ''​%%/​dev/​zero%%''​ este un generator de octeți. Acesta generează atâția octeți cu valoarea zero (**0**)((<​HTML><​p></​HTML>​Valoarea **0** nu înseamnă cifra **0**. Valoarea **0** înseamnă caracterul **(null)** din tabelul [[http://​www.asciitable.com/​|ASCII]]. Caracterul **0** are valoarea **48** în tabelul ASCII.<​HTML></​p></​HTML>​)) cât îi sunt ceruți. Urmăm exemplul:<​HTML></​p></​HTML>​
 +<code bash>
 +student@uso:​~$ cat /dev/zero | xxd
 +00000000: 0000 0000 0000 0000 0000 0000 0000 0000  ................
 +00000010: 0000 0000 0000 0000 0000 0000 0000 0000  ................
 +00000020: 0000 0000 0000 0000 0000 0000 0000 0000  ................
 +00000030: 0000 0000 0000 0000 0000 0000 0000 0000  ................
 +00000040: 0000 0000 0000 0000 0000 0000 0000 0000  ................
 +00000050: 0000 0000 0000 0000 0000 0000 0000 0000  ................
 +00000060: 0000 0000 0000 0000 0000 0000 0000 0000  ................
 +00000070: 0000 0000 0000 0000 0000 0000 0000 0000  ................
 +00000080: 0000 0000 0000 0000 0000 0000 0000 0000  ................
 +[...]
 +^C
 +</​code>​
 +<​HTML><​p></​HTML>​Deoarece citim din generator, comanda ''​%%cat%%''​ va afișa o infinitate de octeți cu valoarea zero. Utilitarul ''​%%xxd%%''​ afișează în hexazecimal textul primit la STDIN. Trecem rezultatul lui ''​%%cat%%''​ prin ''​%%xxd%%''​ deoarece valoarea **0** nu este un caracter printabil. Cu alte cuvinte nu este un caracter obișnuit, ca cele de pe tastatură, deoarece nu are un echivalent grafic. Folosim ''​%%Ctrl+c%%''​ pentru a opri execția.<​HTML></​p></​HTML>​
 +<​HTML><​p></​HTML>​**Exercițiu**:​ Rulați comanda ''​%%cat /​dev/​zero%%''​ pentru a înțelege nevoia utilitarului ''​%%xxd%%''​ din exemplul de mai sus.<​HTML></​p></​HTML>​
 +<​HTML><​blockquote>​
 +<​HTML><​ul></​HTML>​
 +<​HTML><​li></​HTML>​Fișierul ''​%%/​dev/​urandom%%''​ este un alt generator de octeți.<​HTML></​li></​HTML><​HTML></​ul></​HTML>​
 +</​blockquote></​HTML>​
 +<​HTML><​p></​HTML>​Acesta generează atâția octeți cu valoare random cât îi sunt ceruți.<​HTML></​p></​HTML>​
 +<​HTML><​p></​HTML>​**Exercițiu**:​ Rulați comenzile din exemplul anterior, dar acum citiți din ''​%%/​dev/​urandom%%''​.<​HTML></​p></​HTML><​HTML></​li></​HTML><​HTML></​ul></​HTML>​
 +
 +Generatoarele de octeți sunt utile pentru a testa aplicațiile pe care le dezvoltăm. Majoritatea aplicațiilor pe care le vom scrie, ca și cele pe care le utilizăm, citesc și prelucrează informații. Testăm o aplicație pentru că vrem să verificăm că nu avem buguri. Pentru aceasta putem să folosim seturi de date de intrare cât mai variate și mai aleatoare, adică inputuri random. Folosim utilitarul ''​%%dd%%''​ pentru a genera un fișier de 100 MB cu octeți random, ca în exemplul de mai jos:
 +
 +<code bash>
 +student@uso:​~$ dd if=/​dev/​urandom of=rand-100mb count=100 bs=1M
 +100+0 records in
 +100+0 records out
 +104857600 bytes (105 MB, 100 MiB) copied, 1,11416 s, 94,1 MB/s
 +student@uso:​~$ ls -lh rand-100mb
 +-rw-rw-r-- 1 student student 100M nov  8 17:49 rand-100mb
 +</​code>​
 +Am folosit următoarele opțiuni ale utilitarului ''​%%dd%%'':​
 +
 +  * ''​%%if%%''​ - input file - calea către fișierul de unde citim
 +  * ''​%%of%%''​ - output file - calea către fișierul unde scriem
 +  * ''​%%bs%%''​ - block size - dimensiunea unui block citit din **if**
 +  * ''​%%count%%''​ - block count - numărul de block-uri citite
 +
 +**Exercițiu**:​ Creați un fișier numit ''​%%rand-250mb%%''​ folosind utilitarul ''​%%dd%%''​.
 +
 +<​note>​
 +
 +
 +Un caz uzual de utilizare a ''​%%dd%%''​ este suprascrierea unui disc cu informații aleatoare. Această metodă este utilizată ca o formă de securitate atunci când vrem să ștergem informații de pe un disc. Astfel suprascriem datele șterse pentru a preveni posibilitatea recuperării datelor de pe disc. Mai multe informații găsiți [[https://​uwnthesis.wordpress.com/​2014/​07/​26/​kali-how-to-use-dd-to-wipe-your-usb-pen-the-visual-guide/​|aici]].
 +</​note>​
 +
 +=== Exerciții ===
 +
 +  - Afișați primele zece procese sortate în funcție de memoria ocupată (Hint: RSS). Nu uitați să includeți antetul. Redirectați rezultatul în fișierul **top10-rss-consumers**. Modificați comanda astfel încât rezultatul redirectării să nu șteargă conținutul existent.
 +  - Afișați ultimele zece procese sortate în funcție de utilizarea procesorului (Hint: CPU). Nu uitați să includeți antetul. Redirectați rezultatul în fișierul **top10-cpu-consumers**. Modificați comanda astfel încât rezultatul redirectării să nu șteargă conținutul existent.
 +
 +**Note de subsol**
 +
 +==== Cuprins ====
 +
 +{{page>​uso:​laboratoare:​laborator-05:​nav&​noheader&​nofooter&​noeditbutton}}
info1/laboratoare/06.1602068742.txt.gz · Last modified: 2020/11/24 12:51 (external edit)
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