stdin, stdout i stderr su tri ključna toka podataka koji se kreiraju prilikom izvršavanja Linux komande. Ovi tokovi vam omogućavaju da pratite da li se vaši skriptovi šalju ili preusmeravaju, što je od velike važnosti za efikasno upravljanje i dijagnostiku. Hajde da detaljnije istražimo njihovu funkcionalnost.
Kako tokovi povezuju dve tačke
Kada počnete da se upoznajete sa Linux operativnim sistemom i njegovim sličnim Unix verzijama, susrešćete se sa terminima stdin, stdout i stderr. To su tri standardna toka koji se uspostavljaju čim se izvrši neka Linux komanda. U svetu računarstva, tok predstavlja kanal za prenos podataka, a u ovom slučaju, podaci su tekstualnog formata.
Kao i vodeni tokovi, i ovi tokovi podataka imaju dva kraja – izvor i odvod. Svaka Linux komanda koju koristite definiše jedan kraj svakog od ovih tokova. Drugi kraj je određen ljuskom koja je pokrenula komandu. Taj drugi kraj se povezuje sa terminalom, cevovodom, ili preusmerava na datoteku ili drugu komandu, u zavisnosti od komandne linije koja je pokrenula komandu.
Standardni tokovi u Linuxu
U Linux okruženju, stdin predstavlja standardni ulazni tok. On prihvata tekstualne podatke kao ulaz. Izlazni tekst komande se šalje ljusci preko stdout (standardni izlazni) toka. Poruke o greškama koje generiše komanda, se usmeravaju putem stderr (standardni izlaz za greške) toka.
Dakle, postoje dva izlazna toka, stdout i stderr, i jedan ulazni tok, stdin. Razdvajanjem izlaza na normalan izlaz i poruke o greškama, Linux omogućava nezavisno upravljanje ovim tokovima.
Tokovi se tretiraju kao datoteke
U Linux sistemu, tokovi se, kao i većina drugih elemenata, tretiraju kao datoteke. Možete čitati tekst iz datoteke, ili upisivati tekst u datoteku. Obe ove operacije uključuju tok podataka. Dakle, koncept tretiranja toka podataka kao datoteke nije komplikovan.
Svaka datoteka koja je povezana sa procesom dobija jedinstveni identifikacioni broj. Ovaj broj se naziva deskriptor datoteke. Svaki put kada je potrebno izvršiti neku operaciju nad datotekom, deskriptor datoteke se koristi za identifikaciju te datoteke.
Standardne vrednosti deskriptora datoteka za stdin, stdout i stderr su uvek:
0: stdin
1: stdout
2: stderr
Reagovanje na cevovode i preusmeravanja
Da bi se olakšalo razumevanje neke teme, često se koristi pojednostavljena verzija kao uvod. Na primer, kada govorimo o gramatici, često čujemo pravilo „I pre E, osim posle C“. Međutim, u stvarnosti, postoje mnogi izuzeci od ovog pravila.
Slično tome, kada se govori o stdin, stdout i stderr, često se navodi da proces ne zna niti ga interesuje gde će završiti njegovi standardni tokovi. Da li je procesu važno da li njegov izlaz ide na terminal ili će biti preusmeren u datoteku? Može li proces znati da li njegov ulaz dolazi sa tastature ili iz drugog procesa?
Zapravo, proces može saznati te informacije ako to želi, i može promeniti svoje ponašanje u skladu sa tim, ako je softverski inženjer dodao tu funkcionalnost.
Ova promena u ponašanju je laka za uočavanje. Isprobajte ove dve komande:
ls
ls | cat
Komanda ls
se ponaša drugačije kada se njen izlaz (stdout) prosledi drugoj komandi. Sam ls
se prebacuje na prikaz u jednoj koloni, a ne cat
. Isti efekat se dešava ako se izlaz komande ls preusmeri:
ls > capture.txt
cat capture.txt
Preusmeravanje stdout-a i stderr-a
Postoji značajna prednost u činjenici da se poruke o greškama šalju putem zasebnog toka. To znači da možemo preusmeriti izlaz komande (stdout) u datoteku, a istovremeno videti sve poruke o greškama (stderr) na terminalu. Tako možemo odmah reagovati na greške, a takođe sprečavamo da poruke o greškama „kontaminiraju“ datoteku u koju preusmeravamo stdout.
U tekst editor unesite sledeći tekst i sačuvajte ga kao error.sh
:
#!/bin/bash echo "About to try to access a file that doesn't exist" cat bad-filename.txt
Neka skripta bude izvršna pomoću ove komande:
chmod +x error.sh
Prva linija skripte šalje tekst na terminal putem stdout toka. Druga linija pokušava da pristupi datoteci koja ne postoji, što će generisati poruku o grešci koja se šalje putem stderr-a.
Pokrenite skriptu pomoću ove komande:
./error.sh
Vidimo da su oba izlazna toka, stdout i stderr, prikazana na terminalu.
Hajde da pokušamo da preusmerimo izlaz u datoteku:
./error.sh > capture.txt
Poruka o grešci, koja se šalje putem stderr-a, se i dalje prikazuje na terminalu. Možemo proveriti sadržaj datoteke kako bismo videli da li je izlaz sa stdout-a otišao u datoteku.
cat capture.txt
Izlaz sa stdin-a je preusmeren na datoteku, kako smo i očekivali.
Simbol >
za preusmeravanje podrazumevano radi sa standardnim izlazom. Možete koristiti numeričke deskriptore datoteka da odredite koji standardni izlazni tok želite da preusmerite.
Da biste eksplicitno preusmerili stdout, koristite ovu instrukciju za preusmeravanje:
1>
Da biste eksplicitno preusmerili stderr, koristite ovu instrukciju za preusmeravanje:
2>
Hajde da pokušamo ponovo, ovoga puta sa 2>
:
./error.sh 2> capture.txt
Poruka o grešci se sada preusmerava, a echo poruka standardnog izlaza se šalje na terminal:
Poruka sa stderr-a se nalazi u fajlu capture.txt
, kako smo i očekivali.
Preusmeravanje i stdout-a i stderr-a
Ako možemo nezavisno preusmeriti stdout ili stderr u datoteku, onda bi trebalo da možemo da ih preusmerimo istovremeno u dve različite datoteke?
Naravno. Ova komanda će preusmeriti stdout u datoteku pod nazivom capture.txt
, a stderr u datoteku pod nazivom error.txt
.
./error.sh 1> capture.txt 2> error.txt
Pošto su oba izlazna toka (standardni izlaz i standardna greška) preusmerena u datoteke, na terminalu nema nikakvog vidljivog izlaza. Vraćamo se na komandnu liniju, kao da se ništa nije dogodilo.
Proverimo sadržaj svake datoteke:
cat capture.txt
cat error.txt
Preusmeravanje stdout-a i stderr-a u istu datoteku
Imamo situaciju u kojoj svaki od standardnih izlaznih tokova ide u svoju datoteku. Jedina druga kombinacija koju još možemo da isprobamo je da pošaljemo i stdout i stderr u istu datoteku.
Ovo možemo da postignemo sledećom komandom:
./error.sh > capture.txt 2>&1
Hajde da je razložimo:
./error.sh
: Pokreće skriptu error.sh
.
> capture.txt
: Preusmerava stdout tok u datoteku capture.txt
. >
je skraćenica za 1>
.
2>&1
: Koristi instrukciju &>
za preusmeravanje. Ova instrukcija omogućava ljusci da jedan tok preusmeri na isto odredište kao drugi tok. U ovom slučaju, kažemo „preusmeri tok 2, stderr, na isto odredište na koje se preusmerava tok 1, stdout.“
Nema vidljivog izlaza, što je dobar znak.
Proverimo capture.txt
datoteku da vidimo šta se u njoj nalazi.
cat capture.txt
I stdout i stderr tokovi su preusmereni u istu datoteku.
Da biste preusmerili i tiho odbacili izlaz nekog toka, usmerite ga na /dev/null
.
Otkrivanje preusmeravanja unutar skripte
Govorili smo o tome kako komanda može da otkrije da li se neki od tokova preusmerava i može promeniti svoje ponašanje u skladu sa tim. Da li to možemo da postignemo i u sopstvenim skriptama? Da, i to je vrlo jednostavna tehnika za razumevanje i korišćenje.
U tekst editor unesite sledeći tekst i sačuvajte ga kao input.sh
:
#!/bin/bash if [ -t 0 ]; then echo stdin coming from keyboard else echo stdin coming from a pipe or a file fi
Neka skripta bude izvršna pomoću ove komande:
chmod +x input.sh
Pametan deo skripte je test u uglastim zagradama. Opcija -t
(terminal) vraća tačno (0) ako je datoteka povezana sa deskriptorom datoteke vezana za terminal. Mi smo koristili deskriptor datoteke 0
kao argument za test, što predstavlja stdin.
Ako je stdin povezan sa terminalom, test će vratiti tačno. Ako je stdin povezan sa datotekom ili cevi, test će vratiti netačno.
Možemo koristiti bilo koju tekstualnu datoteku za generisanje ulaza u skriptu. U ovom slučaju, koristimo datoteku pod nazivom dummy.txt
.
./input.sh < dummy.txt
Izlaz pokazuje da skripta prepoznaje da ulaz ne dolazi sa tastature, već iz datoteke. Ako bismo želeli, mogli bismo da menjamo ponašanje skripte u zavisnosti od toga.
Ovo je bilo preusmeravanje iz datoteke, probajmo sada sa cevi.
cat dummy.txt | ./input.sh
Skripta prepoznaje da je njen ulaz preusmeren na nju. Ili, preciznije, još jednom prepoznaje da stdin tok nije povezan sa terminalom.
Hajde da pokrenemo skriptu bez cevi ili preusmeravanja.
./input.sh
Stdin tok je povezan sa terminalom, i skripta to pravilno prijavljuje.
Da bismo proverili istu stvar sa izlaznim tokom, potrebna nam je nova skripta. U tekst editor unesite sledeće i sačuvajte kao output.sh
.
#!/bin/bash if [ -t 1 ]; then echo stdout is going to the terminal window else echo stdout is being redirected or piped fi
Neka skripta bude izvršna pomoću sledeće komande:
chmod +x input.sh
Jedina bitna promena u ovoj skripti je test u uglastim zagradama. Koristimo broj 1
da predstavimo deskriptor datoteke za stdout.
Hajde da isprobamo. Prosledićemo izlaz kroz cat
.
./output.sh | cat
Skripta prepoznaje da njen izlaz ne ide direktno na terminal.
Takođe možemo testirati skriptu preusmeravanjem izlaza u datoteku.
./output.sh > capture.txt
Nema izlaza na terminalu, tiho se vraćamo na komandnu liniju, kao što smo i očekivali.
Možemo pogledati datoteku capture.txt
da vidimo šta je snimljeno. Uradite to pomoću ove komande.
cat capture.sh
Jednostavan test u skripti nam pokazuje da se stdout tok ne šalje direktno na terminal.
Ako pokrenemo skriptu bez cevi ili preusmeravanja, ona bi trebalo da detektuje da se stdout isporučuje direktno na terminal.
./output.sh
I to je upravo ono što vidimo.
Tokovi svesti
Znajući kako da utvrdite da li su vaše skripte povezane sa terminalom, cevima ili su preusmerene, omogućava vam da prilagodite njihovo ponašanje u skladu sa tim.
Logovanje i dijagnostički izlaz mogu biti detaljniji ili manje detaljni, u zavisnosti od toga da li izlaz ide na ekran ili u datoteku. Poruke o greškama se mogu logovati u datoteku koja se razlikuje od standardnog izlaza programa.
Kao što je često slučaj, više znanja nam otvara više opcija.