This is an old revision of the document!
În secțiunea anterioară, 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:
Pentru a afișa pe ecran conținutul unui fișier folosim utlitarul cat
. Rulăm comanda de mai jos, pentru a exemplifica:
student@uso:~$ cat ~/uso-lab/labs/05-cli/support/make-folder/hangman.c #include <stdio.h> #include <string.h> int main() { // Get word to guess char answer[128]; printf("Enter word to guess: "); [...]
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:
student@uso:~$ cat /proc/meminfo | grep "Mem" MemTotal: 2041248 kB MemFree: 236092 kB MemAvailable: 874420 kB
Î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"
.
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ținuttail
- afișează ultimele 10 linii din conținut
Valoarea 10 este valoarea implicită a ambelor utilitare, dar putem specifica un alt număr de linii.
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:
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
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ă.
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
.
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:
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
În acest moment am găsit răspunsul căutat, dar avem două mici neajunsuri:
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:
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 [...]
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:
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
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:
SYNOPSIS grep [OPTIONS] PATTERN [FILE...]
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:
student@uso:~$ cat uso-lab/labs/05-cli/support/make-folder/hangman.c | grep gameover int gameover = 0; while (! gameover) { gameover = 1; gameover = 0;
În exemplul de mai sus, operatorul |
trimite textul afișat de comanda cat
către intrarea standard a comenzii grep
. Acesta comandă este un exemplu de oneliner. Vom discuta mai multe despre oneliners în secțiunea următoare.
Comanda următoare este echivalentă cu cea de mai sus:
student@uso:~$ grep gameover uso-lab/labs/05-cli/support/make-folder/hangman.c int gameover = 0; while (! gameover) { gameover = 1; gameover = 0;
Observăm modul de folosire: grep PATTERN cale/către/fișier
.
hangman.c
, pentru a vedea care sunt headerele incluse în acest fișiere (#include <...>
). Observați cât de multe rezultate irelevante ați găsit datorită faptului că am căutat doar caracterul l. Folosiți patternul “include” în încercarea de a restrânge căutarea.
Folosim opțiunea -n
pentru a afișa și numărul liniei care conține patternul căutat:
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) [...]
Implicit, grep caută în mod case-sensitive patternul, așa cum putem observa din exemplul de mai jos:
student@uso:~$ grep Search workspace/C/searching/binary_search.c
Pentru a efectua căutarea textului în mod case-insesnsitive, folosim opțiunea -i
, ca în exemplul de mai jos:
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) [...]
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:
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> [...]
Î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:
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)
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:
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 :
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ă.
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:
student@uso:~$ grep -nri search workspace/C/ | less workspace/C/leetcode/src/700.c:10:struct TreeNode *searchBST(struct TreeNode *root, int val)
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:
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| [...]
Observăm că acum rezultatele conțin doar cuvântul search.
stdio.h
.binarySearch
.quickSort
.