Ce sunt stdin, stdout și stderr pe Linux?

Publicat: 2022-01-29
Fereastra terminalului pe un computer Linux
Fatmawati Achmad Zaenuri/Shutterstock.com

stdin , stdout și stderr sunt trei fluxuri de date create atunci când lansați o comandă Linux. Le puteți folosi pentru a afla dacă scripturile dvs. sunt redirecționate sau redirecționate. Vă arătăm cum.

Fluxurile unesc două puncte

De îndată ce începeți să aflați despre Linux și sistemele de operare asemănătoare Unix, veți întâlni termenii stdin , stdout și stederr . Acestea sunt trei fluxuri standard care sunt stabilite atunci când este executată o comandă Linux. În calcul, un flux este ceva care poate transfera date. În cazul acestor fluxuri, acele date sunt text.

Fluxurile de date, precum fluxurile de apă, au două capete. Au o sursă și o ieșire. Indiferent de comandă Linux pe care o utilizați, oferă un capăt al fiecărui flux. Celălalt capăt este determinat de shell-ul care a lansat comanda. Acest capăt va fi conectat la fereastra terminalului, conectat la o conductă sau redirecționat către un fișier sau altă comandă, conform liniei de comandă care a lansat comanda.

Fluxurile standard Linux

În Linux, stdin este fluxul de intrare standard. Acesta acceptă text ca intrare. Ieșirea textului de la comandă către shell este transmisă prin fluxul stdout (ieșire standard). Mesajele de eroare de la comandă sunt trimise prin fluxul stderr (eroare standard).

Deci puteți vedea că există două fluxuri de ieșire, stdout și stderr , și un flux de intrare, stdin . Deoarece mesajele de eroare și ieșirea normală au fiecare conductă proprie pentru a le transporta către fereastra terminalului, acestea pot fi gestionate independent unul de celălalt.

Fluxurile sunt tratate ca și fișiere

Fluxurile în Linux — ca aproape orice altceva — sunt tratate ca și cum ar fi fișiere. Puteți citi text dintr-un fișier și puteți scrie text într-un fișier. Ambele acțiuni implică un flux de date. Deci conceptul de a gestiona un flux de date ca fișier nu este atât de exagerat.

Publicitate

Fiecărui fișier asociat unui proces i se alocă un număr unic pentru a-l identifica. Acesta este cunoscut sub numele de descriptor de fișier. Ori de câte ori este necesară efectuarea unei acțiuni asupra unui fișier, descriptorul fișierului este utilizat pentru a identifica fișierul.

Aceste valori sunt întotdeauna folosite pentru stdin , stdout, și stderr :

  • 0 : stdin
  • 1 : stdout
  • 2 : stderr

Reacționează la conducte și redirecționări

Pentru a ușura introducerea cuiva la un subiect, o tehnică comună este de a preda o versiune simplificată a subiectului. De exemplu, cu gramatica, ni se spune că regula este „I înainte de E, cu excepția după C”. Dar, de fapt, există mai multe excepții de la această regulă decât sunt cazuri care o respectă.

Într-o ordine similară, atunci când vorbim despre stdin , stdout și stderr , este convenabil să scoatem la trap axioma acceptată că unui proces nici nu știe și nici nu-i pasă unde se termină cele trei fluxuri standard ale sale. Ar trebui unui proces să-i pese dacă ieșirea sa va ajunge la terminal sau este redirecționată într-un fișier? Poate chiar să spună dacă intrarea sa provine de la tastatură sau este introdusă în ea dintr-un alt proces?

De fapt, un proces știe – sau cel puțin poate afla, dacă alege să verifice – și își poate schimba comportamentul în consecință dacă autorul software-ului a decis să adauge această funcționalitate.

Publicitate

Putem observa foarte ușor această schimbare de comportament. Încercați aceste două comenzi:

 ls 

 ls | pisică 

Comanda ls se comportă diferit dacă ieșirea sa ( stdout ) este transmisă în altă comandă. Este ls care comută la o singură coloană de ieșire, nu este o conversie efectuată de cat . Și ls face același lucru dacă rezultatul său este redirecționat:

 ls > capture.txt 

 captură pisică.txt 

Se redirecționează stdout și stderr

Există un avantaj ca mesajele de eroare să fie livrate printr-un flux dedicat. Înseamnă că putem redirecționa ieșirea unei comenzi ( stdout ) către un fișier și totuși vedem orice mesaj de eroare ( stderr ) în fereastra terminalului. Puteți reacționa la erori dacă este necesar, pe măsură ce apar. De asemenea, oprește contaminarea mesajelor de eroare a fișierului în care a fost redirecționat stdout .

Tastați următorul text într-un editor și salvați-l într-un fișier numit error.sh.

 #!/bin/bash

echo „Eu pe punctul de a încerca să accesez un fișier care nu există”
cat bad-filename.txt

Faceți scriptul executabil cu această comandă:

 chmod +x error.sh

Prima linie a scriptului trimite text în fereastra terminalului, prin fluxul stdout . A doua linie încearcă să acceseze un fișier care nu există. Acest lucru va genera un mesaj de eroare care este livrat prin stderr .

Rulați scriptul cu această comandă:

 ./error.sh 

Putem vedea că ambele fluxuri de ieșire, stdout și stderr , au fost afișate în ferestrele terminalului.

Să încercăm să redirecționăm rezultatul către un fișier:

 ./error.sh > capture.txt 

Publicitate

Mesajul de eroare care este livrat prin stderr este încă trimis în fereastra terminalului. Putem verifica conținutul fișierului pentru a vedea dacă ieșirea stdout a mers la fișier.

 captură pisică.txt 

Ieșirea de la stdin a fost redirecționată către fișier așa cum era de așteptat.

Simbolul de redirecționare > funcționează implicit cu stdout . Puteți utiliza unul dintre descriptorii de fișier numeric pentru a indica ce flux de ieșire standard doriți să redirecționați.

Pentru a redirecționa în mod explicit stdout , utilizați această instrucțiune de redirecționare:

 1>

Pentru a redirecționa în mod explicit stderr , utilizați această instrucțiune de redirecționare:

 2>

Să încercăm din nou testul nostru și de data aceasta vom folosi 2> :

 ./error.sh 2> capture.txt 

Mesajul de eroare este redirecționat și mesajul stdout echo este trimis în fereastra terminalului:

Să vedem ce este în fișierul capture.txt.

 captură pisică.txt 

Mesajul stderr este în capture.txt așa cum era de așteptat.

Redirecționarea Atât stdout, cât și stderr

Cu siguranță, dacă putem redirecționa fie stdout , fie stderr către un fișier independent unul de celălalt, ar trebui să le putem redirecționa pe amândouă în același timp, către două fișiere diferite?

Publicitate

Da putem. Această comandă va direcționa stdout către un fișier numit capture.txt și stderr către un fișier numit error.txt.

 ./error.sh 1> capture.txt 2> error.txt 

Deoarece ambele fluxuri de ieșire - ieșire standard și eroare standard - sunt redirecționate către fișiere, nu există nicio ieșire vizibilă în fereastra terminalului. Ne întoarcem la promptul liniei de comandă ca și cum nimic nu s-ar fi întâmplat.

Să verificăm conținutul fiecărui fișier:

 captură pisică.txt
 eroare pisică.txt 

Redirecționarea stdout și stderr către același fișier

Este frumos, avem fiecare dintre fluxurile de ieșire standard care merg la propriul fișier dedicat. Singura altă combinație pe care o putem face este să trimitem atât stdout , cât și stderr la același fișier.

Putem realiza acest lucru cu următoarea comandă:

 ./error.sh > capture.txt 2>&1

Să descompun asta.

  • ./error.sh : Lansează fișierul script error.sh.
  • > capture.txt : redirecționează fluxul stdout către fișierul capture.txt. > este prescurtarea pentru 1> .
  • 2>&1 : Aceasta folosește instrucțiunea de redirecționare &>. Această instrucțiune vă permite să spuneți shell-ului să facă ca un flux să ajungă la aceeași destinație ca un alt flux. În acest caz, spunem „redirecționează fluxul 2, stderr , către aceeași destinație către care este redirecționat fluxul 1, stdout ”.

Nu există nicio ieșire vizibilă. Asta e încurajator.

Să verificăm fișierul capture.txt și să vedem ce este în el.

 captură pisică.txt 

Atât fluxurile stdout , cât și stderr au fost redirecționate către un singur fișier destinație.

Pentru ca rezultatul unui flux să fie redirecționat și aruncat în tăcere, direcționați ieșirea către /dev/null .

Detectarea redirecționării într-un script

Am discutat despre modul în care o comandă poate detecta dacă vreunul dintre fluxuri este redirecționat și poate alege să-și modifice comportamentul în consecință. Putem realiza acest lucru în propriile noastre scenarii? Da putem. Și este o tehnică foarte ușor de înțeles și folosit.

Publicitate

Tastați următorul text într-un editor și salvați-l ca input.sh.

 #!/bin/bash

dacă [-t 0 ]; atunci

  echo stdin care vine de la tastatură
 
altfel

  echo stdin provenind dintr-o conductă sau un fișier
 
fi

Utilizați următoarea comandă pentru a o face executabilă:

 chmod +x input.sh

Partea inteligentă este testul dintre paranteze pătrate. Opțiunea -t (terminal) returnează true (0) dacă fișierul asociat cu descriptorul de fișier se termină în fereastra terminalului. Am folosit descriptorul de fișier 0 ca argument pentru test, care reprezintă stdin .

Dacă stdin este conectat la o fereastră de terminal, testul se va dovedi adevărat. Dacă stdin este conectat la un fișier sau o conductă, testul va eșua.

Putem folosi orice fișier text convenabil pentru a genera intrare în script. Aici folosim unul numit dummy.txt.

 ./input.sh < dummy.txt 

Ieșirea arată că scriptul recunoaște că intrarea nu provine de la o tastatură, ci de la un fișier. Dacă alegeți, puteți modifica comportamentul scriptului în consecință.

Publicitate

Asta a fost cu o redirecționare a fișierului, hai să încercăm cu o conductă.

 manechin de pisică.txt | ./input.sh 

Scriptul recunoaște că intrarea sa este introdusă în el. Sau mai precis, recunoaște încă o dată că fluxul stdin nu este conectat la o fereastră de terminal.

Să rulăm scriptul fără conducte și nici redirecționări.

 ./input.sh 

Fluxul stdin este conectat la fereastra terminalului, iar scriptul raportează acest lucru în consecință.

Pentru a verifica același lucru cu fluxul de ieșire, avem nevoie de un nou script. Introduceți următoarele într-un editor și salvați-l ca output.sh.

 #!/bin/bash

dacă [-t1]; atunci

echo stdout va ajunge la fereastra terminalului
 
altfel

echo stdout este redirecționat sau canalizat
 
fi

Utilizați următoarea comandă pentru a o face executabilă:

 chmod +x input.sh

Singura modificare semnificativă a acestui script este în testul dintre paranteze drepte. Folosim cifra 1 pentru a reprezenta descriptorul de fișier pentru stdout .

Hai să-l încercăm. Vom canaliza ieșirea prin cat .

 ./ieșire | pisică 

Publicitate

Scriptul recunoaște că rezultatul său nu se duce direct la o fereastră de terminal.

De asemenea, putem testa scriptul redirecționând rezultatul către un fișier.

 ./output.sh > capture.txt 

Nu există nicio ieșire în fereastra terminalului, suntem returnați în tăcere la promptul de comandă. Așa cum ne-am aștepta.

Putem privi în interiorul fișierului capture.txt pentru a vedea ce a fost capturat. Utilizați următoarea comandă pentru a face acest lucru.

 captura de pisică.sh 

Din nou, testul simplu din scriptul nostru detectează că fluxul stdout nu este trimis direct la o fereastră de terminal.

Publicitate

Dacă rulăm scriptul fără conducte sau redirecționări, ar trebui să detecteze că stdout este livrat direct în fereastra terminalului.

 ./ieșire.sh 

Și exact asta vedem.

Fluxuri De Conștiință

Știind cum să știi dacă scripturile tale sunt conectate la fereastra terminalului, la o conductă sau sunt redirecționate, vă permite să le ajustați comportamentul în consecință.

Ieșirea de înregistrare și diagnosticare poate fi mai mult sau mai puțin detaliată, în funcție de faptul că merge pe ecran sau într-un fișier. Mesajele de eroare pot fi înregistrate într-un alt fișier decât rezultatul normal al programului.

Așa cum este de obicei cazul, mai multe cunoștințe aduce mai multe opțiuni.

LEGATE: Cele mai bune laptopuri Linux pentru dezvoltatori și entuziaști