====== 7. Redirectări ======
Redirectarile sunt principalul mijloc prin care stocam pe disc, in fisiere, prelucrarile de date facute de scripturi si programe.
===== Subiecte abordate =====
* STDOUT (1)
* STDERR (2)
* STDIN (0)
===== Resurse utile =====
* [[http://books.google.com/books?id=_JFGzyRxQGcC&pg=PA365|Capitolul 12 - Shell scripting]]
* [[http://www.tldp.org/LDP/Bash-Beginners-Guide/html/|TLDP - Bash guide for beginners]]
* [[http://www.cyberciti.biz/open-source/learning-bash-scripting-for-beginners/|Learning Bash Scripting for Beginners]]
===== Exerciții =====
==== Demo-uri ====
=== Lucrul cu redirectari ===
Redirectare ''stdout'' (standard output, în general mesaje afișate prin comenzi similare cu ''printf'' din C). De exemplu, într-un sistem în care avem multe procese, e greu sa urmărim direct în consolă output-ul comenzii ''ps'':
training@box:~$ ps -f -u student > stdout.txt
training@box:~$ cat stdout.txt
Putem redirecta **doar** mesajele de eroare către un fișier. Scenariu: Vrem să găsim toate fișierele cu extensia ''*.conf'' din directorul ''/etc''.
training@box:~$ find /etc -name '*.conf'
(...)
find: `/etc/ppp/peers': Permission denied
(...)
Ne deranjează mesajele de eroare din cauza lipsei drepturilor de citire asupra unor fișiere sau directoare. Pentru aceasta vom folosi:
training@box:~$ find /etc -name '*.conf' 2> errors.txt
training@box:~$ cat errors.txt
Putem face combinații acum: redirectăm erorile într-un fișier și rezultatele în alt fișier:
training@box:~$ find /etc -name '*.conf' 2> errors.txt > stdout.txt
În cazul în care dorim să redirecționăm **toate** mesajele afișate de o comandă, la grămadă, folosim operatorul ''&>'':
training@box:~$ find /etc -name '*.conf' &> find_output.txt
Reamintiți-vă de la procese ''procfs'', montat în ''/proc''. Pentru fiecare proces identificat printr-un PID, aveam directorul ''/proc/19827/fd'', care conținea link-uri simbolice către fișierele deschise de acel proces. Pentru fiecare proces în acel director găseam ''0, 1, 2''. Acestea reprezintă respectiv:
* ''0'' - intrarea standard (stdin). Exemplu: tastatura
* ''1'' - ieșirea standard (stdout). Exemplu: mesaje afișate cu ''printf'' de un program C
* ''2'' - ieșirea standard de eroare (stderr), unde se duc mesaje precum cele afișate de find mai sus.
Putem redirecta outputul și către device-uri virtuale, cum ar fi ''/dev/null''. În general facem acest lucru deoarece vrem să executăm o anumită comandă (într-un program sau într-un script), fără a ne interesa outputul ei. Pentru exemplul cu ''find'' de mai sus, să zicem că dorim să ignorăm erorile:
training@box:~$ find /etc -name '*.conf' 2> /dev/null
Atenție! Toți operatorii de redirectare din acest demo ''2>'', ''&>'', ''>'' trunchiază conținutul fișierului, dacă acesta exista. Ca alternativă aveam //append mode//, care se poate aplica și aici, fără probleme, astfel:
''%%2>>%%'', ''%%&>>%%'', ''%%>>%%''.
=== Investigarea redirectărilor ===
Putem folosi ''lsof'' pentru a verifica modul în care redirectarea afectează descriptorii unui proces.
Într-un tab de terminal porniți un proces ''sleep'' folosind comanda: ''sleep 100''.
În alt tab, pentru a investiga descriptorii procesului sleep folosim comanda ''lsof -p $(pidof sleep)''.
Observăm că descriptorii standard referă terminalul în care a fost rulată comanda, moșteniți de la terminalul din shell-ul folosit.
Acum să invesigăm procesul sleep cu redictări în diverse fișiere. Folosiți comanda ''sleep 100 < /dev/zero > /dev/null 2> error.txt''
Folosim comanda lsof anterioară pentru a investiga descriptorii procesului sleep. Putem observa unde pointează descriptorii standard de fișier pentru procesul pornit.
==== Exercițiu 1 ====
De multe ori dorim să căutăm într-o ierarhie de fișiere și directoare, dar după anumite criterii. Comanda cea mai potrivită în acest caz este ''find''. Folosiți ''find'' pentru a afișa toate fișierele din ierarhia ''/etc/'' (adică toate fișierele din /etc/, din subdirectoarele acestuia, din subdirectoarele subdirectoarelor etc.). **Hint**: Folosiți opțiunea ''-type'' a comenzii find.
Extindeți comanda anterioară pentru a afișa toate fișierele din ierarhia ''/etc/'' al căror nume începe cu litere între //a// și //d//. **Hint**: Folosiți opțiunea ''-name'' a comenzii find și construcția ''[a-d]*'' pentru a indica un șir care începe cu o literă între //a// și //d// urmată de orice altceva.
Extindeți comanda anterioară pentru a afișa toate fișierele din ierahia ''/etc/'' care au permisiunile de forma ''%%rw-------%%'', adică 600. **Hint**: Folosiți opțiunea ''-perm'' urmată de permisiunile căutate în format octal.
Pentru comanda finală, redirectați outputul în fișierul ''~/file_list.txt'' și erorile în ''~/errors.txt''.
==== Exercițiu 2 ====
Schimbați directorul curent în directorul /home/training. Folosiți comanda ''echo'' pentru a afișa pe ecran textul ''al doilea exercițiu''. Redirectați acest text într-un fișier numit ''ex2.txt''.
Folosiți comanda echo pentru a adăuga textul ''e mai lung decat primul'' în fișierul ''ex2.txt'', fără a șterge conținutul său.
Scriind comanda gcc fără niciun parametru, veți primi un mesaj de eroare. Redirectați acest mesaj de eroare folosind un operator de redirectare într-un fişier numit ''gcc_error.txt''. Afișați conținutul fișierului pentru a confirma.
Redirectați ieșirea standard a comenzii ''strace -e open ls /lib'' în fișierul ''strace.out''.
Redirectați ieșirea de eroare standard a comenzii ''strace -e open ls /lib'' în fișierul ''strace.err''.
Redirectați atât ieșirea standard cât și ieșirea de eroare standard a comenzii ''strace -e open ls /lib'' în fișierul ''strace.both''.
Filtrați (folosind ''grep libc'') ieșirea standard a comenzii ''strace -e open ls /lib'' și apoi redirectați-o în ''strace-new.out'' iar ieșirea de eroare standard în ''strace-new.err''.
Filtrați (folosind ''grep proc'') ieșirea de eroare standard a comenzii ''strace -e open ls /lib'' și apoi redirectați-o în ''strace-newer.err'' iar ieșirea standard în ''/dev/null''.
Adăugați output-ul generat la ieșirea de eroare standard și ieșirea standard a comenzii ''strace -e open ls /lib'' în fișierul ''strace.log''. O nouă rulare a comenzii va conduce la adăugarea de informații la sfârșitul acestui fișier.
Folosiți utilitarul ''tee'' atât pentru a afișa la ieșirea standard cât și a scrie în fișierul ''free.txt'' ieșirea comenzii ''free''. Scrierea în fișier trebuie făcută fără a suprascrie ce era deja scris. (Hint: ''man tee'', append)
Explicați diferența de comportament între următoarele două comenzi:
cat / 2>&1 > error.txt
cat / > error.txt 2>&1