103.4 Lecke 1
Tanúsítvány: |
LPIC-1 (101) |
---|---|
Verzió: |
5.0 |
Témakör: |
103 GNU és Unix parancsok |
Fejezet: |
103.4 Folyamok, csövek és átirányítások használata |
Lecke: |
1/2 |
Bevezetés
Minden számítógépes program ugyanazt az általános elvet követi: a valamilyen forrásból kapott adatokat átalakítják, hogy érthető eredményt hozzanak létre. Linux shell környezetben az adatforrás lehet egy helyi fájl, egy távoli fájl, egy eszköz (például egy billentyűzet), stb. A program kimenete általában a képernyőn jelenik meg, de gyakori az is, hogy a kimeneti adatokat egy helyi fájlrendszerben tárolja, egy távoli eszközre küldi, hangszórókon keresztül játssza le, stb.
A Unix által inspirált operációs rendszerek, mint például a Linux, sokféle be- és kimeneti módszert kínálnak. Különösen a fájlleírók (file descriptors) módszer teszi lehetővé, hogy egész számokat dinamikusan hozzárendeljünk az adatcsatornákhoz, így egy processz hivatkozhat rájuk, mint a bemeneti/kimeneti adatfolyamaira.
A szabványos Linux-folyamatok alapértelmezés szerint három kommunikációs csatornát nyitnak meg: a standard input csatornát (legtöbbször egyszerűen stdin), a standard output csatornát (stdout) és a standard error csatornát (stderr). Az ezekhez a csatornákhoz rendelt numerikus fájlleírók: 0
az stdin, 1
az stdout és 2
az stderr. A kommunikációs csatornák a /dev/stdin
, /dev/stdout
és /dev/stderr
speciális eszközökön keresztül is elérhetők.
Ez a három szabványos kommunikációs csatorna lehetővé teszi a programozók számára, hogy olyan kódot írjanak, amely adatokat olvas és ír anélkül, hogy aggódnának amiatt, hogy milyen adathordozóról érkezik vagy hova megy. Ha például egy programnak adathalmazra van szüksége bemenetként, akkor egyszerűen kérhet adatokat a szabványos bemenetről, és bármi is legyen az, amit szabványos bemenetként használnak, biztosítja az adatokat. Hasonlóképpen, a legegyszerűbb módszer, amellyel egy program megjelenítheti a kimenetét, ha azt a standard kimenetre írja. Egy standard shell munkamenetben a billentyűzetet stdin-ként, a monitor képernyőjét pedig stdout és stderr-ként definiáljuk.
A Bash shell képes a kommunikációs csatornák újbóli kiosztására egy program betöltésekor. Lehetővé teszi például, hogy a képernyő mint szabványos kimenet felülbírálható legyen, és a helyi fájlrendszerben lévő fájlt használjuk stdoutként.
Átirányítások
Egy csatorna fájlleírójának a shell környezetében történő újbóli hozzárendelését redirect-nek (átirányítás) nevezzük. Az átirányítást egy speciális karakter határozza meg a parancssoron belül. Például egy folyamat standard kimenetének egy fájlba történő átirányításához a parancs végére a nagyobb mint szimbólum >
kerül, amelyet az átirányított kimenetet fogadó fájl elérési útvonala követ:
$ cat /proc/cpuinfo >/tmp/cpu.txt
Alapértelmezés szerint csak az stdout-ra érkező tartalom kerül átirányításra. Ez azért történik, mert a fájlleíró numerikus értékét közvetlenül a nagyobb mint szimbólum előtt kell megadni, és ha ez nincs megadva, a Bash a standard kimenetet irányítja át. Ezért a >
használata egyenértékű az 1>
használatával (az stdout fájlleíró értéke 1
).
Az stderr tartalmának rögzítéséhez a 2>
átirányítást kell használni. A legtöbb parancssoros program hibakeresési információkat és hibaüzeneteket küld a standard hibacsatornára. Lehetséges például egy nem létező fájl beolvasási kísérlete által kiváltott hibaüzenet rögzítése:
$ cat /proc/cpu_info 2>/tmp/error.txt $ cat /tmp/error.txt cat: /proc/cpu_info: No such file or directory
Mind az stdout, mind az stderr átirányítása ugyanabból a célból történik a &>
vagy a >&
segítségével. Fontos, hogy az amperjel mellé ne tegyünk szóközöket, különben a Bash azt a folyamat háttérben történő futtatására vonatkozó utasításnak fogja venni, és nem az átirányítás végrehajtására.
A cél egy írható fájl elérési útja, például /tmp/cpu.txt
, vagy egy írható fájlleíró. A fájlleíró célpontot a fájlleíró numerikus értéke után egy amperjel jelöli. Például az 1>&2
átirányítja az stdout-ot az stderr-re. Ha ennek ellenkezőjét, stderr-t stdout-ra akarjuk átirányítani, akkor a 2>&1
-t kell használni helyette.
Bár nem túl hasznos, mivel ugyanezt a feladatot rövidebb úton is el lehet végezni, lehetséges az stderr-t átirányítani az stdout-ra, majd átirányítani egy fájlba. Például egy átirányítás, amely az stderr-t és az stdout-ot is egy log.txt
nevű fájlba írja, a következőképpen írható: >log.txt 2>&1
. Az stderr átirányításának fő oka azonban az, hogy lehetővé tegye a hibakeresési és hibaüzenetek elemzését. Lehetséges egy program standard kimenetét egy másik program standard bemenetére átirányítani, de nem lehetséges a standard hiba közvetlen átirányítása egy másik program standard bemenetére. Így a program stderr-re küldött üzeneteit először át kell irányítani az stdout-ra ahhoz, hogy egy másik program stdin-je beolvashassa.
Ha a parancs kimenetét csak el akarjuk dobni, akkor annak tartalmát átirányíthatjuk a /dev/null
speciális fájlba. Például a >log.txt 2>/dev/null
az stdout tartalmát a log.txt
fájlba menti, az stderr-t pedig eldobja. A /dev/null
állományt bármely felhasználó írhatja, de semmilyen adat nem állítható vissza belőle, mivel nem tárolja sehol.
Hibaüzenet jelenik meg, ha a megadott cél nem írható (ha az útvonal mappára vagy csak olvasható fájlra mutat), és a cél nem módosítható. A kimeneti átirányítás azonban megerősítés nélkül felülír egy meglévő írható célt. A kimeneti átirányítások felülírják a fájlokat, kivéve, ha a Bash noclobber
opció engedélyezve van, amit az aktuális munkamenetre a set -o noclobber
vagy a set -C
paranccsal lehet megtenni:
$ set -o noclobber $ cat /proc/cpu_info 2>/tmp/error.txt -bash: /tmp/error.txt: cannot overwrite existing file
A noclobber
opció aktuális munkamenetből történő visszavonásához futtassuk a set +o noclobber
vagy a set +C
parancsot. Ahhoz, hogy a noclobber
opció tartós legyen, a felhasználó Bash-profiljában vagy a rendszerszintű profilban kell szerepelnie.
Még a noclobber
opció engedélyezésével is lehetséges az átirányított adatok hozzáadása a meglévő tartalomhoz. Ez egy átirányítással érhető el, amelyet két nagyobb mint szimbólummal >>
írunk:
$ cat /proc/cpu_info 2>>/tmp/error.txt $ cat /tmp/error.txt cat: /proc/cpu_info: No such file or directory cat: /proc/cpu_info: No such file or directory
Az előző példában az új hibaüzenet a /tmp/error.txt
fájlban lévőhöz lett hozzácsatolva. Ha a fájl még nem létezik, akkor létrejön az új adatokkal.
A folyamat standard bemenetének adatforrása is átrendezhető. A kevesebb, mint szimbólum <
arra szolgál, hogy egy fájl tartalmát átirányítsuk egy folyamat stdin-jébe. Ebben az esetben az adatok jobbról balra áramlanak: az átirányított leíró a kisebb mint szimbólum bal oldalán 0-nak, az adatforrásnak (egy fájl elérési útvonalának) pedig a kisebb mint szimbólum jobb oldalán kell lennie. A uniq
parancs, mint a legtöbb szövegfeldolgozó parancssori segédprogram, alapértelmezés szerint elfogadja az stdin-re küldött adatokat:
$ uniq -c </tmp/error.txt 2 cat: /proc/cpu_info: No such file or directory
A -c
opcióval a uniq
azt jeleníti meg, hogy hányszor szerepel egy ismételt sor a szövegben. Mivel az átirányított fájlleíró numerikus értéke el lett nyomva, a példaparancs a uniq -c 0</tmp/error.txt
paranccsal egyenértékű. A 0
-tól eltérő fájlleíró használatának egy bemeneti átirányításban csak bizonyos kontextusokban van értelme, mert lehetséges, hogy egy program a 3
, 4
stb. fájlleíróknál kérjen adatokat. Valójában a programok bármely 2 feletti egész számot használhatnak új fájlleíróként az adatok be- és kimenetéhez. Például a következő C kód adatokat olvas be a 3
fájlleíróból, és egyszerűen átmásolja a 4
fájlleíróba:
Note
|
A programnak helyesen kell kezelnie az ilyen fájlleírókat, különben érvénytelen olvasási vagy írási műveletet kísérelhet meg, és összeomolhat. |
#include <stdio.h> int main(int argc, char **argv){ FILE *fd_3, *fd_4; // 3-as fájlleíró megnyitása fd_3 = fdopen(3, "r"); // 4-es fájlleíró megnyitása fd_4 = fdopen(4, "w"); // Olvasás a 3-as fájlleíróból char buf[32]; while ( fgets(buf, 32, fd_3) != NULL ){ // Írás a 4-es fájlleíróba fprintf(fd_4, "%s", buf); } // Mindkét fájlleíró bezárása fclose(fd_3); fclose(fd_4); }
A teszteléshez mentsük el a mintakódot fd.c
néven, és fordítsuk le a gcc -o fd fd.c
paranccsal. Ennek a programnak szüksége van arra, hogy a 3. és 4. fájlleíró elérhető legyen, hogy tudjon olvasni és írni rájuk. Példaként a korábban létrehozott /tmp/error.txt
fájlt használhatjuk a 3
fájlleíró forrásaként, a 4
fájlleírót pedig átirányíthatjuk az stdout-ra:
$ ./fd 3</tmp/error.txt 4>&1 cat: /proc/cpu_info: No such file or directory cat: /proc/cpu_info: No such file or directory
A programozó szempontjából a fájlleírók használatával elkerülhető, hogy az opcióelemzéssel és a fájlrendszeri elérési utakkal kelljen foglalkozni. Ugyanaz a fájlleíró akár bemenetként és kimenetként is használható. Ebben az esetben a fájlleírót a parancssorban kisebb mint és nagyobb mint szimbólumokkal definiáljuk, mint például a 3<>/tmp/error.txt
-ben.
Here Document és Here String
A bemenet átirányításának másik módja a Here document és Here string metódusok használata. A Here document átirányítás lehetővé teszi, hogy többsoros szöveget írjunk be, amely az átirányított tartalomként fog szerepelni. Két kisebb mint szimbólum <<<
jelzi a Here document átirányítást:
$ wc -c <<EOF > How many characters (Hány karakter) > in this Here document? (van ebben a Here document-ben?) > EOF 43
A két kisebb mint szimbólum <<
jobb oldalán található az EOF
záró kifejezés. A beszúrási mód befejeződik, amint egy olyan sor kerül beírásra, amely csak a befejező kifejezést tartalmazza. Bármilyen más kifejezés is használható befejező kifejezésként, de fontos, hogy a kevesebb mint szimbólum és a befejező kifejezés közé ne kerüljenek üres karakterek. A fenti példában a két sornyi szöveget a wc -c
parancs küldte el az stdin-be, amely a karakterek számát jeleníti meg. A fájlok bemeneti átirányításához hasonlóan az stdin (0
fájlleíró) feltételezhető, ha az átirányított fájlleíró el van nyomva.
A Here string módszer hasonló a Here document módszerhez, de csak egy sorra vonatkozik:
$ wc -c <<<"How many characters in this Here string?" 41
Ebben a példában a három kisebb, mint jel jobb oldalán lévő sztringet a wc -c
elküldi az stdin-be, amely megszámolja a karakterek számát. A szóközöket tartalmazó sztringeknek idézőjelek között kell lenniük, különben csak az első szó lesz Here stringként használva, a többi pedig argumentumként kerül átadásra a parancsnak.
Gyakorló feladatok
-
A szöveges fájlok mellett a
cat
parancs bináris adatokkal is dolgozhat, például egy blokkeszköz tartalmát küldheti el egy fájlba. Az átirányítás segítségével hogyan tudja acat
elküldeni a/dev/sdc
eszköz tartalmát az aktuális könyvtárban lévősdc.img
fájlba? -
Mi a neve a
date 1> now.txt
parancs által átirányított szabványos csatornának? -
Miután megpróbáltunk felülírni egy fájlt átirányítással, a felhasználó hibaüzenetet kap, amely szerint a
noclobber
opció engedélyezve van. Hogyan lehet anoclobber
opciót kikapcsolni az aktuális munkamenetre? -
Mi lesz a
cat <<.>/dev/stdout
parancs eredménye?
Gondolkodtató feladatok
-
A
cat /proc/cpu_info
parancs hibaüzenetet jelenít meg, mert a/proc/cpu_info
nem létezik. Hova irányítja a hibaüzenetet acat /proc/cpu_info 2>1
parancs? -
Akkor is lehetséges lesz a
/dev/null
-ra küldött tartalmak eldobása, ha anoclobber
opció engedélyezve van az aktuális shell munkamenethez? -
Az
echo
használata nélkül hogyan lehetne a$USER
változó tartalmát átirányítani asha1sum
parancs stdin-jébe? -
A Linux kernel a
/proc/PID/fd/
szimbolikus hivatkozásokat tart fenn minden olyan fájlhoz, amelyet egy folyamat megnyitott, ahol PID a megfelelő folyamat azonosító száma. Hogyan használhatná a rendszergazda ezt a mappát aznginx
által megnyitott naplófájlok helyének ellenőrzésére, ha feltételezzük, hogy a PID-je1234
? -
Aritmetikai számításokat csak a shell beépített parancsaival lehet végezni, de a lebegőpontos számításokhoz speciális programokra van szükség, mint például a
bc
(basic calculator). Abc
programmal még a tizedesjegyek számát is meg lehet adni ascale
paraméterrel. Abc
azonban csak a szabványos bemeneten keresztül fogad el műveleteket, általában interaktív módban beírva. Egy Here string segítségével hogyan küldhetjük el ascale=6; 1/3
lebegőpontos műveletet abc
standard bemenetére?
Összefoglalás
Ez a lecke olyan módszereket mutatott be, amelyekkel egy program a szabványos kommunikációs csatornák átirányításával futtatható. A Linux-folyamatok ezeket a szabványos csatornákat általános fájlleíróként használják az adatok olvasására és írására, így lehetővé téve, hogy tetszőlegesen fájlokra vagy eszközökre változtassuk őket. A lecke a következő lépéseken ment keresztül:
-
Mik azok a fájlleírók és milyen szerepet játszanak a Linuxban.
-
Minden folyamat szabványos kommunikációs csatornái: stdin, stdout és stderr.
-
Hogyan kell helyesen végrehajtani egy parancsot az adatok átirányításával, mind a bemenet, mind a kimenet esetében.
-
Hogyan használjuk a Here Documents és a Here Strings kifejezéseket a bemeneti átirányításokban.
A tárgyalt parancsok és eljárások a következők voltak:
-
Átirányító operátorok:
>
,<
,>>
,<<
,<<<
. -
A
cat
,set
,uniq
éswc
parancsok.
Válaszok a gyakorló feladatokra
-
A szöveges fájlok mellett a
cat
parancs bináris adatokkal is dolgozhat, például egy blokkeszköz tartalmát küldheti el egy fájlba. Az átirányítás segítségével hogyan tudja acat
elküldeni a/dev/sdc
eszköz tartalmát az aktuális mappában lévősdc.img
fájlba?$ cat /dev/sdc > sdc.img
-
Mi a neve a
date 1> now.txt
parancs által átirányított szabványos csatornának?Standard output (standard kimenet) vagy stdout
-
Miután megpróbáltunk felülírni egy fájlt átirányítással, a felhasználó hibaüzenetet kap, amely szerint a
noclobber
opció engedélyezve van. Hogyan lehet anoclobber
opciót kikapcsolni az aktuális munkamenetre?set +C
vagyset +o noclobber
-
Mi lesz a
cat <<.>/dev/stdout
parancs eredménye?A Bash belép a Heredoc beviteli módba, majd kilép, ha csak egy pont jelenik meg egy sorban. A beírt szöveget átirányítja az stdout-ra (a képernyőre).
Válaszok a gondolkodtató feladatokra
-
A
cat /proc/cpu_info
parancs hibaüzenetet jelenít meg, mert a/proc/cpu_info
nem létezik. Hova irányítja a hibaüzenetet acat /proc/cpu_info 2>1
parancs?Az
1
nevű fájlba az aktuális mappában. -
Akkor is lehetséges lesz a
/dev/null
-ra küldött tartalmak eldobása, ha anoclobber
opció engedélyezve van az aktuális shell munkamenethez?Igen, a
/dev/null
egy speciális fájl és nincs rá hatással anoclobber
. -
Az
echo
használata nélkül hogyan lehetne a$USER
változó tartalmát átirányítani asha1sum
parancs stdin-jébe?$ sha1sum <<<$USER
-
A Linux kernel a
/proc/PID/fd/
szimbolikus hivatkozásokat tart fenn minden olyan fájlhoz, amelyet egy folyamat megnyitott, ahol PID a megfelelő folyamat azonosító száma. Hogyan használhatná a rendszergazda ezt a mappát aznginx
által megnyitott naplófájlok helyének ellenőrzésére, ha feltételezzük, hogy a PID-je1234
?Az
ls -l /proc/1234/fd
parancs kiadásával, amely megjeleníti a mappában lévő összes szimbolikus link célpontját. -
Aritmetikai számításokat csak a shell beépített parancsaival lehet végezni, de a lebegőpontos számításokhoz speciális programokra van szükség, mint például a
bc
(basic calculator). Abc
programmal még a tizedesjegyek számát is meg lehet adni ascale
paraméterrel. Abc
azonban csak a szabványos bemeneten keresztül fogad el műveleteket, általában interaktív módban beírva. Egy Here string segítségével hogyan küldhetjük el ascale=6; 1/3
lebegőpontos műveletet abc
standard bemenetére?$ bc <<<"scale=6; 1/3"