====== 5. Funcționarea shell-ului ======
Ne interesează internele shell-ului și modul în care acesta execută comenzi. Urmărim să știm ce facilități ne oferă shell-ului pentru a ne face mai rapid și mai productiv activitățile cu sistemul de operare.
===== Subiecte abordate =====
* Pornirea unui shell: shell-uri și terminale, ''/etc/passwd''
* Scripturi de startup ale shell-ului
* Rularea unei comenzi de către shell
* Subshell-uri
* Variabile shell, variabile de mediu
* Operatori shell
* Caractere speciale shell
* Globbing
==== Bune practici ====
* Comenzi care primesc informații la intrarea standard și comenzi care primesc informații ca parametru: operatorul ''|'' vs. expandarea comenzilor ''%%$(...)%%''
* Folosire variabile de mediu doar la nevoie; de prefixat comenzi cu inițializare de variabile
* Comenzi folosite pentru afișare și comenzi folosite pentru prelucrare
* Măsoară de două ori și taie o dată :-)
* Activare reverse search ''tcsh'': http://stackoverflow.com/a/7771746
==== Utilitare folosite ====
* ''bash'', ''lsof''
* ''echo''
* ''type'', ''which''
* ''env'', ''set''
* ''find'', ''stat'', ''pgrep''
===== Resurse utile =====
* https://www.gnu.org/software/bash/manual/html_node/Shell-Expansions.html#Shell-Expansions
* http://tldp.org/LDP/GNU-Linux-Tools-Summary/html/x11655.htm
==== Slide-uri ====
[[http://koala.cs.pub.ro/training/res/medium-unix/slides/cap-05.pdf|Slide-uri capitol 5]]
===== Exerciții =====
==== Demo-uri ====
Pornirea unui shell folosind programul ''login'' și apoi ''/etc/passwd''. Variabila ''SHELL''
Terminalul unui shell și descriptorii standard de fișier pentru un shell
Ce acțiuni realizează shell-ul la rularea unei comenzi, rularea unei comenzi în background
Determinarea comenzilor builtin și a comenzilor externe (''type'' și ''which'').
Diferența între:
ps ; echo ; echo ; echo ; echo ; echo ; echo ; echo ; echo ; ps
și
ps ; /bin/echo ; /bin/echo ; /bin/echo ; /bin/echo ; /bin/echo ; /bin/echo ; /bin/echo ; /bin/echo ; ps
Crearea de subshell-uri, problema cu
echo | read v
Actualizarea variabilei de mediu ''PATH''. Definirea de noi variabile de mediu. Prefixarea unei comenzi cu inițializarea unei variabile de mediu
Expandarea comenzilor:
stat -c "%s" $(find /etc/ -type f -name '*.conf' -size +5k)
lsof -p $(pgrep bash | tr '\n' ',')
Operații pe șiruri în shell
=== Globbing ===
Dorim să afișăm toate fișierele cu extensia ''.conf'' din ''/etc'', care încep cu ''a, b, c, d'' sau ''e'':
ls -l /etc/[a-e]*.conf
Dorim să afișăm fișierele (sau directoarele) cu extensiile ''.conf'' sau ''.d'' din ''/etc'':
ls -ld /etc/*{.conf,.d}
De ce am folosit parametrul ''-d'' la ''ls''?
Dorim să afișăm fișierele (sau directoarele) cu extensiile ''.conf'' sau ''.d'' din ''/etc'' care nu încep cu ''a, b, c'':
ls -ld /etc/[^abc]*{.conf,.d}
==== Mesaj de întâmpinare în shell ====
Dorim să afișăm un mesaj de întâmpinare custom pentru momentul în care un utilizator deschide un shell. Mesajul vrem să fie
Welcome, , to Pearson-Hardman-Specter. just got Litt-up!
unde '''' este username-ul.
Pentru aceasta va trebui să editați, ca ''root'' (adică folosind ''sudo''), fișierul ''/etc/bash.bashrc'' și să scrieți la **sfârșitul** fișierului comanda dorită. Comanda va fi rulată la orice deschidere de shell nou. Folosiți comanda ''sudo vim /etc/bash.bashrc'' pentru a edita ca root fișierul ''/etc/bash.bashrc''.
Fișierul ''/etc/bash.bashrc'' este un fișier global de configurare a shell-ului. Fișierul este parcurs la fiecare deschidere de shell.
Pentru început afișați șirul ''%%Welcome%%'' la fiecare deschidere de shell. Adică scrieți la sfârșitul fișierului ''/etc/bash.bashrc'' comanda pentru afișarea șirului. Apoi deschideți un shell nou (sau un tab nou de shell pentru verificare).
Pentru a afișa un mesaj folosiți comanda ''echo'' urmată de șirul de afișat. Este recomandat ca șirul de afișat, transmis ca argument comenzii ''echo'' să fie pus între ghilimele (''%%"%%'', //quotes//).
Pentru afișarea șirului dorit, care conține username-ul, folosiți variabila ''USER'', variabilă deja definită în shell. Variabila ''USER'' conține username-ul. Pentru a afișa valoarea unei variabile folosim construcția de forma ''$USER''. De exemplu, pentru a afișa numele de utilizator și un mesaj de salut folosim comanda
echo "Salut, $USER"
Ca să testați deschideți un tab nou de terminal; la deschiderea terminalului vi se va crea shell-ul și vi se va afișa mesajul din ''/etc/bash.bashrc''.
==== Folosire globbing ====
Descărcați și despachetați arhiva de [[http://koala.cs.pub.ro/training/res/medium-unix/arc/cap-05-res.zip|aici]].
Listați, folosind **globbing**, toate imaginile cu extensiile ''bmp, jpg, png, gif'' din directorul rezultat în urma dezarhivării.
Pentru a lista toate fișierele cu extensiile ''bmp'', ''jpg'', ''png'' și ''gif'' folosiți operatorii de globbing ''*'' (//star//) si ''{opt1,opt2,opt3}'' (acolade). Un exemplu simplu de utilizare (porniți de la acesta) este
ls practic/*/*.png
==== Expandarea comenzii ====
Creați o arhivă ''tar.gz'' cu fișierele din ierarhia ''/etc/'' care au extensia ''.conf'' și au dimensiunea mai mare de ''5KB''.
Folosiți comanda ''tar'' și apoi expandare de comandă ''find''. Vedeți și exemplele de comenzi de la demo-ul legat de expandarea comenzilor.
Creați o arhivă ''zip'' cu fișierele din ierarhia ''/usr/include'' care conțin șirul ''epoll'',
Folosiți opțiunea ''-r'' a comenzii ''grep'' pentru a căuta recursiv într-o ierarhie. Folosiți opțiunea ''-l'' a comenzii ''grep'' pentru a afișa doar numele fișirelor găsite.
==== Afișare caractere speciale ====
Inițializați variabila ''text'' la un șir de caractere.
Adică rulați ceva de genul:
text="mellon"
Afișați la ieșirea standard mesajul ''%%"Variabila text are valoarea '"...'". Valorea poate fi actualizata."%%''. În mesaj, toate caracterele ghilimele (''"'') și apostrof (''%%'%%'') se vor afișa întocmai. Iar în loc de ''...'' puneți valoarea variabile ''text''.
Pentru a afișa ghilimele atunci când deja vă aflați între ghilimele va trebui să le escapați. Escaparea se face folosind ''\'' (//backslash//).
Alternativa este să închideți ghilimele inițiale și apoi să afișați ghilimelele pe care vreți să afișați între apostrofuri. Invers pentru escaparea de apostrofuri.
Nu puteți escapa apostrofuri câtă vreme vă aflați între apostrofuri.
De exemplu dacă vrem să afișăm șirul ''%%ana'are"mere%%'' putem folosi
echo ana"'"are'"'mere
Urmăriți ce face comanda
echo "'"'"'ana-are-mere'"'"'"
==== Afișare fișiere localizate ====
Folosiți comanda ''locate'' pentru a afișa fișierele din sistem care au extensia ''.conf''.
Pentru fișierele de mai sus afișați directoarele din care fac parte.
Folosiți comanda ''dirname'' pentru extragerea directoarelor din lista de fișiere extrasă mai sus. Folosiți expandarea comenzilor, adică construcția ''%%$(...)%%'', în conjuncție cu comanda ''locate'' rulată mai sus.
Eliminați duplicatele.
Folosiți operatorul ''|'' pentru a redirecta comanda de mai sus către comanda ''sort -u''.
Pentru directoarele de mai sus afișați numele directorului și inode-ul, separate prin virgulă ('','').
Folosiți comanda ''stat'' cu opțiunea ''-c'' și formatul corespunzător.
**Bonus**: Sortați directoarele de mai sus în ordinea inode-ului. Afișați numele directorului și inode-ul (separate prin virgulă ('','')).
==== Afișare fișiere executabile pentru procese ====
Afișați procesele al căror proces părinte este ''init'', procesul cu PID-ul ''1''.
Pentru procesele de mai sus afișați **doar** comanda completă.
Filtrați doar acele comenzi care încep cu ''/'' (adică este calea completă către executabil).
Selectați **doar** calea către executabil, fără argumente către acesta.
Pentru executabilele de mai sus afișați numele și timpul ultimei schimbării (//change time//), separate prin virgulă ('','').
Folosiți comanda ''stat''.
Sortați executabilele de mai sus în ordinea timpului ultimei schimbări.
Sortarea poate fi simplă, nu este nevoie de sortare numerică. Formatul datei afișat de ''stat'' permite sortare de orice fel.
==== Creare fișiere ====
Creați 100 de fișiere cu numele ''%%"myfile-XY.txt"%%'', unde ''XY'' este indexul fișierului între ''00'' și ''99''.
Folosiți comenzile ''seq'' și ''touch''.
Ca model folosiți-vă de comanda
seq -f "%02g" 1 100
Între ghilimele poate apărea un șir complet. Gândiți-vă că trebuie să generați șiruri de forma ''%%myfile-XY.txt%%''.
==== Expandare aritmetică ====
Din fișierul de [[http://lpic.ro/res/skel/sandbox.kext_iOS9.3|aici]] dorim să extragem partea care începe de la offset-ul ''0x13000'' (în hexazecimal) până la sfârșit. Puneți conținutul într-un alt fișier. Afișați conținutul primilor 16 octeți din fișier în format hexazecimal; output-ul trebuie să fie de forma ''0080 b67f 6a01 7900 1180 0000 b57f b57f''.
Pentru a extrage o parte dintr-un fișier folosiți comanda ''dd''. Folosiți opțiunea ''skip'' a ''dd''.
Pentru că operați pe octeți, nu pe blocuri, va trebui să configurați pentru ''dd'' dimensiunea blocului la ''1'' folosind opțiunea ''bs''.
Dacă avem un număr în hexazecimal putem folosi construcția de expandare aritmetică ''%%$(...)%%'' pentru a-l converti în zecimal. De exemplu:
user@hostname:~$ echo $((0x10)), $((0x20)), $((0x100))
16, 32, 256