Ce sunt stdin, stdout și stderr pe Linux?

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ă învățați despre sistemele de operare Linux și Unix, veți întâlni termenii stdin, stdout și stederr. Acestea sunt trei fluxuri standard care sunt stabilite atunci când o comandă Linux este executată. Î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.

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 de fișier este folosit 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, acolo sunt mai multe excepții de la această regulă decât sunt cazuri care i se supun.

  Cum să joci Path of Exile pe Linux

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

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

ls

ls | cat

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

ls > capture.txt într-o fereastră de terminal” width=”646″ height=”57″ onload=”pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”  onerror=”this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”></p>
<pre>cat capture.txt</pre>
<p><img loading=

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 încă vedem orice mesaje 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 "About to try to access a file that doesn't 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

./error.sh > capture.txt într-o fereastră de terminal” width=”646″ height=”57″ onload=”pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”  onerror=”this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”></p>
<p>Mesajul de eroare care este livrat prin stderr este încă trimis în fereastra terminalului.  Putem verifica conținutul fișierului pentru a vedea dacă rezultatul stdout a ajuns la fișier.</p>
<pre>cat capture.txt</pre>
<p><img loading=

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.

  Încă 6 widget-uri KDE Plasma 5 pentru desktopul dvs. Linux

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

./error.sh 2> capture.txt într-o fereastră de terminal” width=”646″ height=”57″ onload=”pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”  onerror=”this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”></p>
<p>Mesajul de eroare este redirecționat și mesajul stdout echo este trimis în fereastra terminalului:</p>
<p ><img class=

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?

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

./error.sh 1> capture.txt 2> error.txt într-o fereastră de terminal” width=”646″ height=”57″ onload=”pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”  onerror=”this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”></p>
<p>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.</p>
<p><img loading=

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

cat capture.txt
cat error.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”.

./error.sh > capture.txt 2&>1 într-o fereastră de terminal” width=”646″ height=”57″ onload=”pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”  onerror=”this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”></p>
<p>Nu există nicio ieșire vizibilă.  Este încurajator.</p>
<p><img loading=

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

cat capture.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.

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

#!/bin/bash

if [ -t 0 ]; then

  echo stdin coming from keyboard
 
else

  echo stdin coming from a pipe or a file
 
fi

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

chmod +x input.sh

Partea inteligentă este testați între paranteze drepte. Opțiunea -t (terminal) returnează adevărat (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.

  Cum se instalează Sublime Merge pe Linux

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 

The output shows that the script recognizes that the input isn’t coming from a keyboard, it is coming from a file. If you chose to, you could vary your script’s behavior accordingly.

That was with a file redirection, let’s try it with a pipe.

cat dummy.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

if [ -t 1 ]; then

echo stdout is going to the terminal window
 
else

echo stdout is being redirected or piped
 
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.

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

./output | cat

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.

cat capture.sh

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

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

./output.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.