Mi az stdin, stdout és stderr Linuxon?

Az stdin, stdout és stderr három adatfolyam, amely egy Linux-parancs indításakor jön létre. Segítségükkel megállapíthatja, hogy a szkriptjeit csővezetékben vagy átirányítja-e. Megmutatjuk, hogyan.

A streamek két pontot egyesítenek

Amint elkezdi megismerni a Linux és a Unix-szerű operációs rendszereket, találkozni fog az stdin, stdout és stederr kifejezésekkel. Ezek három szabványos adatfolyam amelyek egy Linux-parancs végrehajtásakor jönnek létre. A számítástechnikában az adatfolyam olyan dolog, amely képes adatokat továbbítani. Ezen adatfolyamok esetében ez az adat szöveg.

Az adatfolyamoknak, akárcsak a vízfolyamoknak, két vége van. Van forrásuk és kiáramlásuk. Bármelyik Linux-parancs is, amelyet használ, minden adatfolyam egyik végét biztosítja. A másik végét a parancsot elindító shell határozza meg. Ez a vég csatlakozik a terminálablakhoz, egy csőhöz, vagy át lesz irányítva egy fájlra vagy más parancsra, a parancsot elindító parancssor szerint.

A Linux Standard Streams

Linuxban az stdin a szabványos bemeneti adatfolyam. Ez szöveget fogad bemenetként. A parancs szövegkimenete a shellbe az stdout (standard out) adatfolyamon keresztül történik. A parancsból származó hibaüzenetek az stderr (normál hiba) adatfolyamon keresztül kerülnek elküldésre.

Így láthatja, hogy két kimeneti adatfolyam van, az stdout és az stderr, valamint egy bemeneti adatfolyam, az stdin. Mivel a hibaüzenetek és a normál kimenet saját csatornával rendelkezik, amely a terminálablakba viszi őket, egymástól függetlenül kezelhetők.

Az adatfolyamokat fájlokként kezelik

A Linuxban az adatfolyamokat – mint szinte minden mást – úgy kezelik, mintha fájlok lennének. Szöveget olvashat egy fájlból, és szöveget írhat fájlba. Mindkét művelet adatfolyamot foglal magában. Tehát az adatfolyam fájlként való kezelésének koncepciója nem túl bonyolult.

Minden egyes folyamathoz társított fájl egyedi számot kap az azonosításhoz. Ezt fájlleírónak nevezik. Amikor egy műveletet kell végrehajtani egy fájlon, a fájlleíró a fájl azonosítására szolgál.

Ezeket az értékeket mindig az stdin, stdout és stderr használja:

0: stdin
1: stdout
2: stderr

Reagálás a csövekre és az átirányításokra

Annak érdekében, hogy megkönnyítsük valakinek a bevezetést egy tantárgyba, egy általános technika a téma egyszerűsített változatának tanítása. Például a nyelvtannál azt mondják nekünk, hogy a szabály „I előtt E, kivéve a C után”. De valójában ott több kivétel ez alól mint vannak olyan esetek, amelyek engedelmeskednek neki.

  Video csengő felszerelése

Hasonló módon, amikor stdin-ről, stdout-ról és stderr-ről beszélünk, célszerű azt az elfogadott axiómát kifejteni, hogy egy folyamat nem tudja, és nem is érdekli, hol végződik három szabványos adatfolyama. Egy folyamatnak törődnie kell-e azzal, hogy a kimenete a terminálra kerül, vagy átirányítja-e egy fájlba? Még azt is meg tudja mondani, hogy a bemenete a billentyűzetről érkezik-e, vagy egy másik folyamatból van-e rávezetve?

Valójában egy folyamat tudja – vagy legalábbis megtudhatja, ha úgy dönt, hogy ellenőrzi –, és ennek megfelelően megváltoztathatja a viselkedését, ha a szoftver szerzője úgy döntött, hogy hozzáadja ezt a funkciót.

Ezt a viselkedésbeli változást nagyon könnyen láthatjuk. Próbáld ki ezt a két parancsot:

ls

ls | cat

Az ls parancs másként viselkedik, ha a kimenete (stdout) egy másik parancsba kerül. Ez az ls, amely egyetlen oszlopos kimenetre vált, nem a cat által végrehajtott átalakítás. És az ls ugyanezt teszi, ha a kimenete át van irányítva:

ls > capture.txt

ls > capture.txt egy terminálablakban” width=”646″ height=”57″ onload=”pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”  onrror=”this.onrror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”></p>
<pre>cat capture.txt</pre>
<p><img loading=

stdout és stderr átirányítása

Előnyös, ha a hibaüzeneteket egy dedikált adatfolyam továbbítja. Ez azt jelenti, hogy átirányíthatjuk egy parancs kimenetét (stdout) egy fájlba, és továbbra is láthatunk hibaüzeneteket (stderr) a terminálablakban. Ha kell, akkor reagálhat a hibákra, ahogy azok előfordulnak. Ezenkívül megakadályozza, hogy a hibaüzenetek beszennyezzék azt a fájlt, amelybe az stdout át ​​lett irányítva.

Írja be a következő szöveget egy szerkesztőbe, és mentse el egy error.sh nevű fájlba.

#!/bin/bash

echo "About to try to access a file that doesn't exist"
cat bad-filename.txt

Tegye végrehajthatóvá a szkriptet ezzel a paranccsal:

chmod +x error.sh

A szkript első sora visszaadja a szöveget a terminálablakba az stdout adatfolyamon keresztül. A második sor egy nem létező fájlhoz próbál hozzáférni. Ez hibaüzenetet generál, amely az stderr-n keresztül érkezik.

Futtassa a szkriptet ezzel a paranccsal:

./error.sh

Láthatjuk, hogy mindkét kimeneti adatfolyam, az stdout és az stderr, megjelenik a terminálablakokban.

Próbáljuk meg átirányítani a kimenetet egy fájlba:

./error.sh > capture.txt

./error.sh > capture.txt egy terminálablakban” width=”646″ height=”57″ onload=”pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”  oneror=”this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”></p>
<p>Az stderr-n keresztül küldött hibaüzenet továbbra is elküldésre kerül a terminálablakba.  Ellenőrizhetjük a fájl tartalmát, hogy az stdout kimenet a fájlhoz ment-e.</p>
<pre>cat capture.txt</pre>
<p><img loading=

Az stdin kimenete a várt módon át lett irányítva a fájlba.

A > átirányítási szimbólum alapértelmezés szerint az stdout-tal működik. A numerikus fájlleírók egyikével jelezheti, hogy melyik szabványos kimeneti adatfolyamot szeretné átirányítani.

Az stdout kifejezett átirányításához használja ezt az átirányítási utasítást:

1>

Az stderr kifejezett átirányításához használja ezt az átirányítási utasítást:

2>

Próbáljuk meg újra a tesztet, és ezúttal a 2>-t használjuk:

./error.sh 2> capture.txt

./error.sh 2> capture.txt egy terminálablakban” width=”646″ height=”57″ onload=”pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”  oneror=”this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”></p>
<div style=

A hibaüzenet átirányításra kerül, és az stdout echo üzenet elküldésre kerül a terminálablakba:

Az stderr üzenet a vártnak megfelelően a capture.txt fájlban található.

Az stdout és az stderr átirányítása

Biztos, hogy ha az stdout vagy az stderr fájlokat egymástól függetlenül át tudjuk irányítani egy fájlra, akkor mindkettőt egyszerre, két különböző fájlra kell átirányítanunk?

Igen. Ez a parancs az stdout-ot a capture.txt fájlba, az stderr-t pedig az error.txt nevű fájlba irányítja.

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

./error.sh 1> capture.txt 2> error.txt egy terminálablakban” width=”646″ height=”57″ onload=”pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”  onrror=”this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”></p>
<p>Mivel mindkét kimeneti adatfolyam – a szabványos kimenet és a szabványos hiba – át van irányítva a fájlokhoz, nincs látható kimenet a terminál ablakát.  Visszatérünk a parancssori prompthoz, mintha semmi sem történt volna.</p>
<p><img loading=

Nézzük meg az egyes fájlok tartalmát:

cat capture.txt
cat error.txt

Az stdout és az stderr átirányítása ugyanabba a fájlba

Ez szép, minden szabványos kimeneti adatfolyam a saját dedikált fájljához megy. Az egyetlen másik kombináció, amit tehetünk, az az, hogy az stdout és az stderr fájlokat is elküldjük ugyanabba a fájlba.

Ezt a következő paranccsal érhetjük el:

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

Bontsuk szét.

./error.sh: Elindítja az error.sh parancsfájlt.
> capture.txt: Átirányítja az stdout adatfolyamot a capture.txt fájlba. > az 1> rövidítése.
2>&1: Ez a &> átirányítási utasítást használja. Ez az utasítás lehetővé teszi, hogy utasítsd a shell-t, hogy az egyik adatfolyam ugyanahhoz a célhoz kerüljön, mint egy másik adatfolyam. Ebben az esetben azt mondjuk, hogy „irányítsa át a 2. adatfolyamot, stderr, ugyanarra a célhelyre, ahová az 1. adatfolyamot (stdout) átirányítja.”

./error.sh > capture.txt 2&>1 terminálablakban” width=”646″ height=”57″ onload=”pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”  onerror=”this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);”></p>
<p>Nincs látható kimenet.  Ez biztató.</p>
<p><img loading=

Nézzük meg a capture.txt fájlt, és nézzük meg, mi van benne.

cat capture.txt

Mind az stdout, mind az stderr adatfolyamot egyetlen célfájlba irányították át.

Ha egy adatfolyam kimenetét át akarja irányítani és csendben el akarja dobni, irányítsa a kimenetet a /dev/null könyvtárba.

Átirányítás észlelése szkripten belül

Megbeszéltük, hogyan képes egy parancs észlelni, ha valamelyik adatfolyam át van irányítva, és hogyan módosíthatja a viselkedését ennek megfelelően. Meg tudjuk valósítani ezt a saját forgatókönyveinkben? Igen. És ez egy nagyon könnyen megérthető és alkalmazható technika.

Írja be a következő szöveget egy szerkesztőbe, és mentse el input.sh néven.

#!/bin/bash

if [ -t 0 ]; then

  echo stdin coming from keyboard
 
else

  echo stdin coming from a pipe or a file
 
fi

Használja a következő parancsot, hogy végrehajtható legyen:

chmod +x input.sh

Az okos rész az teszt a szögletes zárójelben. A -t (terminál) opció true (0) értéket ad vissza, ha a fájl a fájlleíróhoz van társítva a terminál ablakban fejeződik be. A 0 fájlleírót használtuk a teszt argumentumaként, amely az stdin-t képviseli.

  VR Shinecon Virtual Reality Headset Review

Ha az stdin terminálablakhoz csatlakozik, a teszt igaznak bizonyul. Ha az stdin fájlhoz vagy csőhöz csatlakozik, a teszt sikertelen lesz.

Bármilyen kényelmes szövegfájlt használhatunk a szkripthez való bevitelhez. Itt a dummy.txt nevű fájlt használjuk.

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

A szkript felismeri, hogy a bemeneti bemenetet csőbe vezetik. Pontosabban, ismét felismeri, hogy az stdin adatfolyam nincs terminálablakhoz csatlakoztatva.

Futtassuk a szkriptet se pipes, se átirányítás nélkül.

./input.sh

Az stdin adatfolyam csatlakozik a terminál ablakhoz, és a szkript ennek megfelelően jelenti ezt.

Ahhoz, hogy ugyanezt a kimeneti adatfolyammal ellenőrizhessük, új szkriptre van szükségünk. Írja be a következőt egy szerkesztőbe, és mentse output.sh néven.

#!/bin/bash

if [ -t 1 ]; then

echo stdout is going to the terminal window
 
else

echo stdout is being redirected or piped
 
fi

Használja a következő parancsot, hogy végrehajtható legyen:

chmod +x input.sh

Az egyetlen jelentős változás ebben a szkriptben a szögletes zárójelben lévő tesztben található. Az 1-es számjegyet használjuk az stdout fájlleírójának jelölésére.

Próbáljuk ki. A kimenetet a katán keresztül vezetjük.

./output | cat

A szkript felismeri, hogy a kimenete nem megy közvetlenül terminálablakba.

A szkriptet úgy is tesztelhetjük, hogy a kimenetet átirányítjuk egy fájlba.

./output.sh > capture.txt

Nincs kimenet a terminálablakba, csendben visszatérünk a parancssorba. Ahogy vártuk.

Belenézhetünk a capture.txt fájlba, hogy megnézzük, mit rögzítettünk. Ehhez használja a következő parancsot.

cat capture.sh

A szkriptünk egyszerű tesztje ismét azt észleli, hogy az stdout adatfolyam nem közvetlenül egy terminálablakba kerül.

Ha a szkriptet csővezetékek vagy átirányítások nélkül futtatjuk, akkor észlelnie kell, hogy az stdout közvetlenül a terminálablakba kerül.

./output.sh

És pontosan ezt látjuk.

A Tudatfolyamok

Ha tudja, hogyan állapíthatja meg, hogy a szkriptek a terminálablakhoz vagy egy csőhöz csatlakoznak-e, vagy át vannak-e irányítva, akkor ennek megfelelően módosíthatja a viselkedésüket.

A naplózási és diagnosztikai kimenet többé-kevésbé részletes lehet, attól függően, hogy a képernyőre vagy egy fájlra kerül. A hibaüzenetek naplózhatók a normál programkimenettől eltérő fájlba.

Ahogy az lenni szokott, a több tudás több lehetőséget kínál.