This is an old revision of the document!


Laborator 06 - Îmbunătățirea lucrului în linia de comandă

Scurtături în terminal

Tab completion

Funcția de tab completion este probabil una dintre cele mai utile funcții expuse de către terminal. Prin simpla apăsare a tastei Tab în timp ce scriem numele unei comenzi, al unei opțiuni a unei comenzi sau calea către un director sau fișier, terminalul va completa în mod automat textul. În cazul în care există mai multe opțiuni pentru auto-complete, prin dubla apăsare a tastei Tab ne va sugera opțiunile de auto-complete.

În imaginea de mai jos putem observa că pentru comanda cd D funcția de Tab completion a găsit mai multe opțiuni valide pentru auto-complete. În astfel de scenarii, cu mai multe opțiuni valide, apăsarea tastei Tab o singură dată nu produce niciun rezultat; trebuie să apăsăm tasta Tab de două ori consecutiv pentru a genera afișarea opțiunilor de auto-complete.

student@uso:~$ cd D
Desktop/   Documents/ Downloads/
student@uso:~$ cd D

Funcția de auto-complete este extrem de utilă și îmbunătățește semnificativ viteza cu care realizăm acțiuni în terminal.

Funcția este extrem de utilă atunci când lucrăm cu nume de fișiere, directoare și căi din sistem. În loc să scriem manual o cale către un nume foarte lung, lăsăm tasta Tab să facă asta pentru noi.

Atunci când avem o eroare în comandă (am scris greșit o anumită parte din numele comenzii sau al fișierului, fișierul nu există, etc.), tasta Tab nu produce nici un rezultat. Acesta este un alt motiv pentru care să folosim tasta Tab.

Folosiți funcția de Tab completion cât mai des cu putință1).

Shellul implementează funcția de a reține istoricul comenzilor pe care le-am executat. Pentru a vedea istoricul curent putem rula comanda history. Vom obține un rezultat asemănător cu cel de mai jos:

student@uso:~$ history
[...]
21  ls
22  cd sorting/
23  ls -l
24  ls
25  cd
26  ls ~/Desktop ~/Documents ~/Downloads
27  ls ~/Desktop
28  ls Desktop/todos.txt
29  cp Desktop/todos.txt cp
30  ls
31  rm cp
[...]

Ciclăm prin comenzile date anterior folosind combinația de taste Arrow Up sau Ctrl+p, respectiv Arrow Down sau Ctrl+n.

Exercițiu: Ciclați prin istoricul de comenzi folosind combinația de taste Ctrl+p, respectiv Ctrl+n.

Căutarea în istoricul comenzilor

Terminalul ne pune la dispoziție un mod mai inteligent de a căuta în istoricul comenzilor prin combinația de taste Ctrl+r, ordinea căutării fiind de la cea mai recentă comandă la cea mai veche. Funcția este cunoscută sub numele de history search.

Pentru a porni căutarea, apăsați combinația de taste Ctrl+r și începeți să scrieți o parte din textul comenzii pe care o căutați, de exemplu cd.

(reverse-i-search)`cd': cd workspace

De aici, avem următoarele opțiuni:

  • Căutăm în continuare o comandă care conține șirul cd, folosind combinația de taste Ctrl+r
  • Rulăm comanda pe care am găsit-o, folosind combinația de taste Ctrl+o
  • Anulăm căutarea comenzii și revenim la starea inițială, folosind combinația de taste Ctrl+g

Căutarea este incrementală. Adică se rafinează pe măsură ce tastăm un caracter. Orice caracter apăsat rafinează căutarea.

Textul căutat se poate afla oriunde în interiorul comenzii; nu trebuie să fie primele litere din comandă. Pentru exemplul de mai sus, căutarea folosind textul work ar fi produs același rezultat:

(reverse-i-search)`work': cd workspace

Ne găsim des în situația în care căutăm o comandă în istoric folosind funcția de history search, modificăm un argument al comenzii și apoi o executăm. Pentru navigarea în cadrul textului comenzii putem folosi Arrow Keys, iar pentru ștergeri putem folosi tasta Backspace sau Del.

Terminalul ne pune la dispoziție și o serie de scurtături cu ajutorul cărora putem face realiza aceeași acțiune mai rapid. Dacă vreți să vă impresionați prietenii, acesta este un mod simplu, dar eficient, de a o face.

Pentru a naviga în corpul textului putem folosi combinațiile de taste:

  • Ctrl+a - mută cursorul la începutul liniei
  • Ctrl+e - mută cursorul la sfârșitul liniei
  • Ctrl+f - mută cursorul cu un caracter înainte
  • Ctrl+b - mută cursorul cu un caracter înapoi
  • Alt+f - mută cursorul cu un cuvânt înainte
  • Alt+b - mută cursorul cu un cuvânt înapoi

Pentru a efectua ștergeri în corpul textului putem folosi combinațiile de taste:

  • Ctrl+k - șterge tot textul de la cursor până la sfârșitul liniei
  • Ctrl+u - șterge tot textul de la cursor până la începutul liniei
  • Alt+d - șterge tot textul de la cursor până la sfârșitul cuvântului

Textul șters este salvat într-un registru și poate fi folosit folosind combinația de taste Ctrl+y. Funcționalitatea este similară cu procesul de Cut (Ctrl+k, Ctrl+u sau Alt+d) și Paste (Ctrl+y).

Extra: Exerciții

Rulați comanda ls Documents/ Downloads/ Desktop/ Pictures/ Music/ înainte de a vă apuca de exerciții.

  1. Apăsați tasta Ctrl+p pentru a accesa comanda rulată anterior.
  2. Plasați-vă la începutul comenzii folosind combinația de taste Ctrl+a.
  3. Plasați-vă la sfârșitul comenzii folosind combinația de taste Ctrl+e.
  4. Mergeți, cuvânt cu cuvânt, la începutul comenzii folosind combinația de taste Alt+b.
  5. Mergeți, cuvânt cu cuvânt, la sfârșitul comenzii folosind combinația de taste Alt+f.
  6. Rulați comanda ls Docuents/ Downlads/ Dektop/ Pitures/ Muic/.
  7. Apăsați tasta Ctrl+p pentru a accesa comanda rulată anterior. Corectați typourile (greșelile de scriere) din comanda anterioară. Folosiți combinațiile de taste Ctrl+f, Ctrl+b pentru a deplasa cursorul în cadrul comenzii.
  8. Apăsați tasta Ctrl+p pentru a accesa comanda rulată anterior (comanda corectată). Avansați până la începutul cuvântului Desktop/. Ștergeți tot până la final folosind combinația de taste Ctrl+k. Acum anulați comanda curentă apăsând combinația de taste Ctrl+c. În acest moment, textul pe care l-ați șters folosind Ctrl+k (Desktop/ Pictures/ Music/) se află într-un buffer. O să rulați comanda ls pe textul din buffer. Scrieți comanda ls și apoi apăsați combinația de taste Ctrl+y. Textul a fost scris din buffer în continuarea comenzii ls (scrisă de voi).
  9. Rulați comanda ls Documents/ Downloads/ Desktop/ Pictures/ Music/. Apăsați tasta Ctrl+p pentru a accesa comanda rulată anterior (comanda corectată). Avansați până la începutul cuvântului Pictures/. Ștergeți cuvântul folosind combinația de taste Alt+d. Acum anulați comanda curentă apăsând combinația de taste Ctrl+c. În acest moment, textul pe care l-ați șters folosind Alt+d (Pictures) se află într-un buffer. O să rulați comanda ls pe textul din buffer. Scrieți comanda ls și apoi apăsați combinația de taste Ctrl+y. Textul a fost scris din buffer în continuarea comenzii ls (scrisă de voi).

Inspectarea sistemului de fișiere

Cea mai importantă comandă

Așa cum spuneam mai devreme, marele avantaj al utilizării terminalului este că ne ajută să rezolvăm sarcini foarte rapid. Rezolvăm sarcini folosind utilitarele pe care le avem disponibile în linia de comandă, fie că acestea fac parte din sistemul nostru sau le-am instalat.

Cel mai important utilitar pe care îl avem la dispoziție este man. Utilitarul man ne deschide pagina de manual în care este documentat un alt utilitar pe care dorim să-l folosim.

student@uso:~$ man
What manual page do you want?

Putem consulta însăși pagina de manual a utilitarului man

student@uso:~$ man man

Vom fi întâmpinați de următorul program interactiv:

MAN(1)                        Manual pager utils                        MAN(1)
 
NAME
       man - an interface to the on-line reference manuals
 
SYNOPSIS
       man  [-C  file]  [-d]  [-D]  [--warnings[=warnings]]  [-R encoding] [-L
       locale] [-m system[,...]] [-M path] [-S list]  [-e  extension]  [-i|-I]
       [--regex|--wildcard]   [--names-only]  [-a]  [-u]  [--no-subpages]  [-P
       pager] [-r prompt] [-7] [-E encoding] [--no-hyphenation] [--no-justifi‐
       cation]  [-p  string]  [-t]  [-T[device]]  [-H[browser]] [-X[dpi]] [-Z]
       [[section] page[.section] ...] ...
       man -k [apropos options] regexp ...
       man -K [-w|-W] [-S list] [-i|-I] [--regex] [section] term ...
       man -f [whatis options] page ...
       man -l [-C file] [-d] [-D] [--warnings[=warnings]]  [-R  encoding]  [-L
       locale]  [-P  pager]  [-r  prompt]  [-7] [-E encoding] [-p string] [-t]
       [-T[device]] [-H[browser]] [-X[dpi]] [-Z] file ...
       man -w|-W [-C file] [-d] [-D] page ...
       man -c [-C file] [-d] [-D] page ...
       man [-?V]
 
 Manual page man(1) line 1 (press h for help or q to quit)

Observăm că ultima linie din terminal, Manual page man(1) line 1 (press h for help or q to quit), ne oferă mai multe informații:

  • Ne aflăm pe prima linie din prima pagină a manualului
  • Putem apăsa tasta h pentru a acesa meniul de ajutor
  • Putem apăsa tasta q pentru a ieși din manual

Navigăm cu câte o linie de terminal în joș și în sus folosind folosind tastele Ctrl+n și Ctrl+p. Putem folosi tastele Ctrl+f și Ctrl+b pentru a naviga, cu câte un ecran de terminal, în jos și în sus în pagină. Mai simplu, putem folosi tasta Enter pentru a naviga cu câte o linie în jos și tasta Space pentru a naviga cu câte un ecran în jos. Navigăm la începutul paginii folosind tasta g. Navigăm la sfârșit paginii folosind tasta G.

Putem folosi tastele j și k ca alternative pentru Arrow Down și Arrow Up. Astfel suntem mai rapizi pentru că nu ne mai mutăm mâna de pe tastele caractere.

Folosim man ca să vedem dacă un utilitar oferă o anumită funcționaltiate. Citim întreaga pagină de manual ca să vedem toate funcționalitățile sau căutăm o funcționalitate folosind cuvinte cheie. Pașii pentru căutarea unui cuvânt cheie sunt următorii:

  1. Pentru a porni funcția de căutare apăsăm tasta / în sesiunea interactivă din man.
  2. În continuare vom introduce textul pe care dorim să-l căutăm: poate să fie un cuvântul cheie pe care îl știm deja sau orice text care sperăm că ne duce la rezultatul dorit.
  3. Acum apăsăm tasta Enter. Vom fi duși la primul rezultat care se potrivește căutării, dacă acesta există.
  4. Dacă vrem să navigăm la următorul rezultat apăsăm tasta n. Dacă vrem să navigăm la un rezultat anterior apăsăm tasta N.

Căutarea2) are loc de la poziția curentă în pagină către sfârșitul paginii. Dacă am navigat deja în interiorul paginii, trebuie să avem în vedere că rezultatul de interes al căutării noastre se poate afla undeva între începutul paginii și poziția noastră curentă3).

Interpretarea paginii de manual

La o primă vedere, textul paginii de manual poate fi intimidant; unele utilitare au mai multe opțiuni și argumente, unele opționale, altele nu. O să trecem prin sintaxă și o să vedem că lucrurile sunt mult mai simple decât par. Să analizăm pagina de manual a utilitarului ls; man ls:

LS(1)                            User Commands                           LS(1)
 
NAME
       ls - list directory contents
 
SYNOPSIS
       ls [OPTION]... [FILE]...
 
DESCRIPTION
       List  information  about  the FILEs (the current directory by default).
       Sort entries alphabetically if none of -cftuvSUX nor --sort  is  speci‐
       fied.
 
       Mandatory  arguments  to  long  options are mandatory for short options
       too.
 
       -a, --all
              do not ignore entries starting with .
 
       -A, --almost-all
              do not list implied . and ..
 
       --author
 Manual page ls(1) line 1 (press h for help or q to quit)
  • Prima secțiune care ne interesează este “DESCRIPTION”. Citim descrierea și ne dăm seama dacă utilitarul ne va ajuta în rezolvarea sarcinii pe care o avem. În cazul utilitarului ls, descrierea ne informează că acesta afișează informații despre fișierele din calea indicată, sau din directorul curent atunci când nu specificăm o cale.
  • Cea de-a doua secțiune care ne interesează este “SYNOPSIS”. Aceasta ne spune cum putem să rulăm utilitarul, ce opțiuni și argumente sunt opționale (pot lipsi) și ce opțiuni și argumente sunt obligatorii.
SYNOPSIS
       ls [OPTION]... [FILE]...

Sintaxa [ ] ne spune că acea categorie este opțională. Astfel, pentru ls, deducem că atât opțiunile ([OPTION]...) cât și argumentele ([FILE]..., calea către fișiere sau directoare) sunt opționale. Cele trei puncte ... înseamnă mai multe din categoria precedentă: deci [OPTION]... înseamnă că nu suntem limitați la o singură opțiune, dar opțiunile pot să și lipsească în totalitate datorită [ ].

O comandă poate avea atât opțiuni, cât și argumente. Opțiunile îi spun unei comenzi cum să își modifice comportamentul, și de obicei sunt precedate de - (ex. -l, --verbose, etc.). Argumentele îi spun unei comenzi pe ce să acționeze.

În exemplul de mai jos:

student@uso:~$ ls -l Desktop/

Avem utilitarul ls care primește opțiunea -l și argumentul Desktop/.

  • Ultima observație pe care o facem este că opțiunile unei comenzi pot avea o formă prescurtată, -a, sau o formă lungă, --all. Nu este obligatoriu ca o opțiune să expună ambele forme, deși majoritatea o fac. Opțiunile în formă prescurtată pot fi concatenate și precedate de un singur -, ca în exemplul de mai jos:

    student@uso:~$ ls -la Desktop/
  • Exerciții

    Deschideți pagina de manual a utilitarului ls.

    1. Căutați opțiunea -a. Rulați comanda ls -a.
    2. Căutați opțiunea -d. Rulați comanda ls -d.
    3. Căutați opțiunea -F. Rulați comanda ls -F.
    4. Căutați cuvântul cheie list. Treceți la următoarea apariție a cuvântului cheie până ajungeți la opțiunea -l.
    5. Mergeți la finalul paginii folosind tasta G. Căutați cuvântul cheie color până ajungeți la opțiunea --color (Hint: ?).

    Explorarea sistemului de fișiere: comanda ls

    În laboratorul Lucrul cu fișiere am văzut cum folosim comanda ls pentru a afișa conținutul unui director și pentru a explora sistemul de fișiere. În continuare vom vedea cum folosim ls pentru a afișa mai multe informații despre conținutul unui director sau despre fișiere.

    Afișarea fișierelor ascunse

    În mediul linux, un fișier este ascuns dacă numele său începe cu caracterul . (punct). În mod implicit, utilitarul ls omite fișierele ascunse. Pentru a afișa fișierele ascunse folosim opțiunea -a (all).

    student@uso:~$ ls -a
    .              .emacs.d         .ssh                       Pictures
    ..             .gconf           .sudo_as_admin_successful  Public
    .ICEauthority  .gitconfig       .tmux                      Templates
    .bash_aliases  .gnome2          .tmux.conf                 Videos
    .bash_history  .gnome2_private  .vim                       examples.desktop
    .bash_logout   .gnupg           .viminfo                   uso.git
    .bashrc        .java            .vimrc                     vm-actions-log.txt
    .cache         .lesshst         Desktop                    workspace
    .config        .local           Documents
    .dbus          .mozilla         Downloads
    .emacs         .profile         Music

    Observăm că avem o mulțime de fișiere ascunse prezente în directorul nostru home. Multe dintre acestea sunt fișiere de configurare (.bashrc, .vimrc, etc.) folosite de diferite programe instalate pe sistemul nostru. Vom vorbi mai multe despre acestea în viitorul apropriat.

    Afișarea informațiilor extinse despre fișiere

    De cele mai multe ori suntem interesați să aflăm mai multe informații despre fișiere: cum ar fi tipul fișierului, permisiuni, ownership, dimensiunea și data ultimei modificări. Toate acestea sunt afișate prin utilizarea opțiunii -l:

    student@uso:~$ ls -l
    total 60
    drwxr-xr-x  2 student student 4096 aug  6  2018 Desktop
    drwxr-xr-x  3 student student 4096 aug 20  2018 Documents
    drwxr-xr-x  2 student student 4096 aug 11 19:35 Downloads
    drwxr-xr-x  2 student student 4096 aug  6  2018 Music
    drwxr-xr-x  3 student student 4096 aug 31 23:26 Pictures
    drwxr-xr-x  2 student student 4096 aug  6  2018 Public
    drwxr-xr-x  2 student student 4096 aug  6  2018 Templates
    drwxr-xr-x  2 student student 4096 aug  6  2018 Videos
    -rw-r--r--  1 student student 8980 aug  6  2018 examples.desktop
    drwxr-xr-x 14 student student 4096 aug 20  2018 uso.git
    -rw-r--r--  1 student student 4827 aug 21  2018 vm-actions-log.txt
    drwxr-xr-x  4 student student 4096 aug 13 18:38 workspace

    Vom analiza informațiile afișate pentru directorul Desktop.

    drwxr-xr-x  2 student student 4096 aug  6  2018 Desktop

    Vom începe cu prima coloană din exemplul de mai sus: drwxr-xr-x. Aceasta este formată din zece caractere care formează patru grupuri:

    • Primul grup este format dintr-un singur caracter, și denotă tipul fișierului. În cazul de față, caracterul d ne informează că ne uităm la un fișier de tip director. În cazul fișierelor obișnuite (text, imagini, etc.) primul caracter este -, așa cum putem observa în cazul fișierului examples.desktop.
    • Cel de-al doilea grup este format din următoarele trei caractere și denotă permisiunile pe care le are utilizatorul care deține fișierul asupra fișierului. Caracterele sunt în ordine r (read) permisiuni de citire, w (write) permisiuni de scriere și x (execute) permisiuni de rulare. Dacă utilizatorul nu are o anumită permisiune, caracterul corespunzător este înlocuit de caracterul -. Spunem că aceste permisiuni se aplică pentru User. Mai multe despre permisiuni in laboratoarele viitoare, deoarece sunt un topic foarte important.
    • Cel de-al treilea grup este format din următoarele trei caractere și denotă permisiunile asupra fișierului pe care le au membrii grupului care dețin fișierul. Permisiunile rămân din setul rwx. Spunem că aceste permisiuni se aplică pentru Group.
    • Cel de-al patrulea grup este format din ultimele trei caractere și denotă permisiunile pe care le are orice utilizator care nu deține fișierul și nici nu face parte din grupul care deține fișierul. Permisiunile rămân din setul rwx. Spunem că aceste permisiuni se aplică pentru Others.

    Acum, pe baza informațiilor din prima coloană, putem spune următoarele despre fișierul Desktop:

    1. Acesta este un fișier de tip director (d)
    2. Utilizatorul care îl deține are drepturi de citire (r), scriere (w) și execuție (x)
    3. Grupul care îl deține are drepturi de citire (r), NU are drepturi de scriere (-) și are drepturi de execuție (x)
    4. Iar orice alt utilizator are drepturi de citire (r), NU are drepturi de scriere (-) și are drepturi de execuție (x).

    Pentru a putea deschide un director este necesar să avem drepturi de execuție (x) asupra acestuia. Trebuie să avem drepturi de execuție indiferent că vrem să navigăm în interiorul său sau să afișăm conținutul directorului. Pentru a crea noi fișiere și directoare în cadrul acestuia, avem nevoie de drepturi de scriere (w).

  • Cea de-a treia coloană ne spune care este utilizatorul care deține fișierul. Astfel observăm că directorul Desktop este deținut de către utilizatorul student. Asta înseamnă că permisiunile rwx corespund utilizatorului student.

  • Cea de-a patra coloană ne spune care este grupul care deține fișierul. Astfel observăm că directorul Desktop este deținut de către grupul student. Asta înseamnă că permisiunile r-x se aplică oricărui utilizator care este membru al grupului student.

  • Cea de-a cincea coloană ne arată dimensiunea fișierului, exprimată în octeți. Putem să-i cerem utilitarului ls să ne afișeze dimensiunea folosind multiplii (K(ilo), M(ega), G(iga), etc) utilizând opțiunea -h (human readable)

    student@uso:~$ ls -lh
    total 60K
    drwxr-xr-x  2 student student 4,0K aug  6  2018 Desktop
    [...]
  • Ultimele coloane ne arată data ultimei modificări, în ordinea lună, zi, an.

  • Afișarea informațiilor extinse despre un fișier de tip director

    Am observat că, în mod implicit, utilitarul ls ne afișază informații despre conținutul unui director atunci când primește calea către un director ca argument:

    student@uso:~$ ls -l Desktop/
    total 0
    -rw-r--r-- 1 student student 0 sep  2 19:39 todos.txt

    Pentru a-i specifica lui ls că suntem interesați de informații despre fișierul de tip director, și nu despre conținutul său, folosim opțiunea -d.

    student@uso:~$ ls -ld Desktop/
    drwxr-xr-x 2 student student 4096 sep  2 19:39 Desktop/
    1. Afișați conținutul directoarelor /home, Downloads și /tmp.
    2. Aflați care sunt permisiunile pe care le are orice utilizator asupra directoarelor /home, /home/student și /tmp.

    Selectarea multiplor fișiere folosind globbing

    Caracterul special *

    În sintaxa globbing, caracterul * poate fi înlocuit cu orice caracter de oricâte ori, sau poate lipsi cu totul. În directorul nostru home (~), executăm următoarele comenzi:

    student@uso:~$ ls
    Desktop    Downloads  Pictures  Templates  examples.desktop  vm-actions-log.txt
    Documents  Music      Public    Videos     uso.git           workspace
     
    student@uso:~$ ls -d D*
    Desktop  Documents  Downloads
     
    student@uso:~$ ls -d Music*
    Music

    Observăm că în expresia D*, caracterul * înglobează toate caracterele care urmează literei D: “esktop”, “ocuments” și “ownloads”. Observăm că în cazul expresie Music*, * nu ține locul nici unui caracter.

    Extra: Folosirea ad-litteram a caracterelor speciale

    Există cazuri când numele fișierelor conțin caractere speciale. Unele fișiere pot fi prefixate cu o categorie din care fac parte, ca în exemplul de mai jos:

    student@uso:~/uso-lab/labs/05-cli/support$ ls tutorial/uni/ 
    '[USO] Course 01.pdf'  '[USO] Course 02.pdf'

    În exemplul de mai sus, fișierele pdf de curs sunt prefixate cu numele materiei: [USO]. Vrem să îi spunem sintaxei de globbing că în acest caz, șirul [USO] nu trebuie tratat ca o expresie, ci ca un șir de caracter normale. Pentru a face acest lucru, încadrăm șirul între :

    student@uso:~/uso-lab/labs/05-cli/support$ ls support-globbing/"[USO]"*
    'support-globbing/[USO] cursuri 1.ppt'   'support-globbing/[USO] slides 1.ppt'
    'support-globbing/[USO] cursuri 10.ppt'  'support-globbing/[USO] slides 10.ppt'
    'support-globbing/[USO] cursuri 2.ppt'   'support-globbing/[USO] slides 2.ppt'
    'support-globbing/[USO] cursuri 3.ppt'   'support-globbing/[USO] slides 3.ppt'
    'support-globbing/[USO] cursuri 4.ppt'   'support-globbing/[USO] slides 4.ppt'
    'support-globbing/[USO] cursuri 5.ppt'   'support-globbing/[USO] slides 5.ppt'
    'support-globbing/[USO] cursuri 6.ppt'   'support-globbing/[USO] slides 6.ppt'
    'support-globbing/[USO] cursuri 7.ppt'   'support-globbing/[USO] slides 7.ppt'
    'support-globbing/[USO] cursuri 8.ppt'   'support-globbing/[USO] slides 8.ppt'
    'support-globbing/[USO] cursuri 9.ppt'   'support-globbing/[USO] slides 9.ppt'

    Citim expresia "[USO]"*: orice fișier al cărui nume începe cu șirul de caractere [USO] și este urmat de orice caracter. Operația prin care eliminăm semnificația specială a unui caracter poartă numele de escaping; cu alte cuvinte, informal, spunem că am făcut escaping semnificației speciale a sintaxei []. Termenul vine de la cuvântul escape (a scăpa), și exprimă că scăpăm de semnificația specială a unui caracter / set de caractere.

    Exerciții

    Pentru exercițiile următoare vom folosi fișierele din directorul de suport ~/uso-lab/labs/05-cli/support/support-globbing.

    1. Creați un director numit pdfs. Mutați toate fișierele cu extensia .pdf din directorul curent în directorul pdfs.
    2. Creați un director numit cursuri/anul-I. De ce nu funcționează crearea directorului? Există directorul cursuri? Mutați toate fișierele care conțin cuvintele curs sau slide în directorul creat. Extra: Folosiți sintaxa *{curs,slide}*.
    3. Creați un director numit Excursie Brasov, 2020-2021. Mutați fișierele DCIM din intervalul 1400 - 1700 în directorul creat.

    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șierul Makefile pentru a vedea cum compilăm și rulăm 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.

    Utilitarul find

    Utilitarul find îndeplinește scopul evident de a 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.

    student@uso:~$ man find
     
    SYNOPSIS
           find  [-H]  [-L]  [-P]  [-D  debugopts]  [-Olevel]  [starting-point...]
           [expression]

    Să clonăm un repository cu algoritmi de sortare:

    student@uso:~$ mkdir workspace
    student@uso:~$ cd workspace
    student@uso:~/workspace$ git clone https://github.com/TheAlgorithms/C.git
    student@uso:~/workspace$ cd C

    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:

    student@uso:~/workspace/C$ cd ../.. 
    student@uso:~$ find . -name "*search*"
    ./workspace/C/searching
    ./workspace/C/searching/linear_search.c
    ./workspace/C/searching/other_binary_search.c
    ./workspace/C/searching/binary_search.c
    ./workspace/C/searching/modified_binary_search.c
    ./workspace/C/searching/jump_search.c
    ./workspace/C/searching/interpolation_search.c
    ./workspace/C/searching/fibonacci_search.c
    ./workspace/C/searching/ternary_search.c
    ./workspace/C/searching/pattern_searc h
    ./workspace/C/searching/pattern_search/naive_search.c
    ./workspace/C/searching/pattern_search/boyer_moore_search.c
    ./workspace/C/searching/pattern_search/rabin_karp_search.c
    ./workspace/C/data_structures/binary_trees/binary_search_tree.c

    În exemplul de mai sus observăm 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*". Există mai multe opțiuni pentru căutarea cu find, prezente în manual.

    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.

    Inspectarea fișierelor

    Inspectarea rapidă 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 utilitarului 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/citim 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 cu ajutorul altor comenzi.

    Căutarea informației într-un fișier

    Pentru a vedea rapid conținutul unui fișier folosim utilitarul less.

    De fapt, comanda man folosește utilitarul less pentru a afișa paginile de manual. less este pagerul implicit în majoritatea distribuțiilor Linux.

    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:

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

    Observăm că acum avem o sesiune interactivă în interiorul căreia putem explora fișierul.

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

    Î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
    1. Analizați, folosind less, algoritmii de căutare din fișierele workspace/C/searching/linear_search.c și workspace/C/searching/binary_search.c. Ce implementare este mai eficientă: binary_search sau linear_search?
    2. Folosiți utilitarul find pentru a găsi fișierul sursă care conține algoritmul de sortare quick_sort. Analizați implementarea acestuia folosind utilitarul less.
    3. Folosiți utilitarul find pentru a găsi fișierul sursă care conține algoritmul de sortare merge_sort. Analizați implementarea acestuia folosind utilitarul less.
    4. 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:

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

    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 argument 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". Despre operatorul | vom vorbi mai jos.

    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

    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:

    • Ne lipsește antetul (aflat pe prima linie), 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:

    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
    Exerciții
    1. Afișați primele zece procese sortate în funcție de memoria ocupată (Hint: RSS). Nu uitați să includeți antetul.
    2. 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, 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 interesează. La începutul acestui laborator, dar și de-a lungul materiei, am folosit utilitarul grep ca să filtrăm rezultatul unei comenzi.

    Comanda grep este una dintre cele mai folosite în linia 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 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)
     
    [...]

    Î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 Înlănțuirea comenzilor în funcție de succes sau eșec.

    Comanda următoare este echivalentă cu cea de mai sus:

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

    Observăm modul de folosire: grep PATTERN cale/către/fișier.

    Exerciții

    1. 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 importante: 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.
    2. Căutați patternul “arr” în fișierul binary_search.c.
    3. Căutați patternul “binarysearch1” în fișierul binary_search.c pentru a vedea cum este apelată funcția de căutare.

    Extra: Opțiuni uzuale ale grep

    Afișarea numărului liniei care conține pattern-ul

    Folosim opțiunea -n pentru a afișa și numărul liniei care conține pattern-ul 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)
    [...]
    Căutarea case-insensitive

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

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

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

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

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

    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.

    Exerciții
    1. Găsiți toate fișierele care includ headerul stdio.h.
    2. Găsiți toate aparițiile patternului binarySearch.
    3. Găsiți toate aparițiile patternului quickSort.

    Cuprins

    1) Putem să ne găsim în situația în care ecranul terminalului nostru este plin cu rezultatele comenzilor rulate anterior sau cu opțiuni afișate de către auto-complete. Putem să curățăm ecranul folosind comanda clear. O alternativă mai rapidă este să folosim combinația de taste Ctrl+l. Aceasta va produce același rezultat (va curăța ecranul) și are avantajul că poate fi folosită în timp ce scriem deja o comandă.
    2) Căutarea este case-sensitive. Putem să schimbăm acest comportament prin introducerea opțiunii -I în sesiunea interactivă, înainte de a porni căutarea. Dacă doriți să aflați mai multe despre opțiunile pe care le putem introduce apăsați tasta h într-o sesiune interactivă și căutați textul “OPTIONS”.
    3) Putem folosi tasta ? pentru a porni o căutare de la poziția curentă către începutul paginii. Alternativ, putem naviga la începutul paginii prin apăsarea unei singure taste (g) și apoi pornim căutarea / de acolo.
    uso/laboratoare/laborator-07.1664572662.txt.gz · Last modified: 2022/10/01 00:17 by mihai_daniel.soare
    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