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.
Tartalomjegyzék
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.
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
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
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
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
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.”
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.
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.shThe 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.shA 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.shAz 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 fiHasználja a következő parancsot, hogy végrehajtható legyen:
chmod +x input.shAz 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 | catA 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.txtNincs 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.shA 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.