6. Átirányítások

Az eddigi példákban a parancsok a képernyőre írták a kimenetüket. Eddig nem volt fontos, hogy ezt a kérdést tisztázzuk, de ebben a fejezetben pontosítanunk kell, a kimenet valójában nem a képernyőre, hanem az ún. standard outputra kerül (ami alapértelmezésben az a képernyő, amit a bejelentkezésed során látsz). Ez a kimenet megváltoztatható, lehetőséged van arra, hogy azt átirányítsd egy fájlba, valamilyen eszközre vagy akár egy másik parancs bemenetére.

A be- és kimeneti csatornák

6.1. A kimenet átirányítása

Egy parancs kimenetének átirányításához a > karaktert kell használnod a parancs leírásának végén. Erre érdemes úgy gondolnod, mint egy nyílhegyre, ami az átirányítás céljára mutat. Első példáinkban ez a cél egy fájl, a /tmp/lista.txt lesz.

feri@columbo:~/demo$ ls -l /etc/d*.conf >/tmp/lista.txt

A parancs lefutása során nem jelenik meg semmi a képernyőn, mert az, amit az ls kiírt volna, az a /tmp/lista.txt fájlba került. Nézzük meg, így van-e, írjuk ki a képernyőre a fájl tartalmát! Ehhez a cat parancsot fogom használni.

feri@columbo:~/demo$ cat /tmp/lista.txt
-rw-r--r-- 1 root root 2969 márc  15  2012 /etc/debconf.conf
-rw-r--r-- 1 root root  604 okt   20  2011 /etc/deluser.conf

A kimeneti fájl a parancs hatására automatikusan létrejön, ha korábban létezett, a korábbi tartalmát a rendszer törli, a helyét az új tartalom váltja fel. Ha nem ezt szeretnéd, hanem a fájl eredeti tartalmához hozzá szeretnéd fűzni az új tartalmat, a > helyett a >> karaktereket kell használnod. Az előző példában létrehozott /tmp/lista.txt tartalmát most az /etc könyvtár s*.conf fájljainak tartalomjegyzék soraival bővítem:

feri@columbo:~/demo$ ls -l /etc/s*.conf >>/tmp/lista.txt
feri@columbo:~/demo$ cat /tmp/lista.txt
-rw-r--r-- 1 root root 2969 márc  15  2012 /etc/debconf.conf
-rw-r--r-- 1 root root  604 okt   20  2011 /etc/deluser.conf
-rw-r--r-- 1 root root 10344 jan   15  2014 /etc/sensors3.conf
-rw-r--r-- 1 root root  7096 febr  28  2014 /etc/smartd.conf
-rw-r--r-- 1 root root  2084 ápr    1  2013 /etc/sysctl.conf

A >> használata miatt most a /tmp/lista.txt tartalmát nem írta felül az újabb parancs kimenete.

6.2. A hibacsatorna

Végezzünk el egy kísérletet (már ha ebben az esetben lehet ezt a szót használni)! Létrehozok egy könyvtárat „kétszer”. A második esetben hibaüzenetet fogok kapni, amit szeretnék átirányítani azért, hogy ne csúfítsa el a képernyőt. Az átirányítás célja a /dev/null lesz.

feri@columbo:~/demo$ mkdir teszt
feri@columbo:~/demo$ mkdir teszt
mkdir: nem lehet a következő könyvtárat létrehozni: ”teszt”: A fájl már létezik
feri@columbo:~/demo$ mkdir teszt >/dev/null
mkdir: nem lehet a következő könyvtárat létrehozni: ”teszt”: A fájl már létezik

Sajnos hiába alkalmaztam az átirányítást, ebben az esetben valamiért nem működik. Hogy lehet ez?

A programok megírásakor a hibaüzeneteket nem ugyanazzal a kiíró utasítással írják ki, mint amit a normál üzenetek esetén használnak. C#-ban a kiíró utasítás a Console.Writeline(), C++-ban a cout. Ha hibaüzenetet írnak ki, nem ezeket használják, hanem azokat, amelyek a hibacstornára írnak, ez a C#-ban Console.Error.WriteLine(), a C++-ban a cerr. Ez ad lehetőséget arra, hogy az operációs rendszer szintjén is szétválaszthasd a normál üzeneteket a hibaüzenetektől, mert az előbbiek a standard outputra, utóbbiak a standard errorra íródnak.

A hibacsatornára írt kimenetek átirányítására a 2> jelölést kell használni. A fenti példát most helyesen megírva, a hibaüzenet célja most a /dev/null lesz, a képernyőn nem jelenik meg.

feri@columbo:~/demo$ mkdir teszt 2>/dev/null

A két átirányítást együtt is használhatod. Az alábbi parancsban a normál kimenet a /tmp/kimenet.txt, a hibaüzenetek a /tmp/hibak.txt fájlba kerül.

feri@columbo:~/demo$ command >/tmp/kimenet.txt 2>/tmp/hibak.txt

Ha a kimenetet és a hibákat is ugyanabba fájlba szeretnéd irányítani, egy rövidebb írásmódot is alkalmazhatsz. A >/tmp/uzenetek.txt 2>&1 azt jelenti, hogy a kimenet kerüljön a /tmp/uzenetek.txt fájlba, a hiba pedig íródjon ugyanebbe.

feri@columbo:~/demo$ command >/tmp/uzenetek.txt 2>&1

Megjegyzés

Mi az a /dev/null? Most nem szeretném még részletesen elmagyarázni, az eszkozfajlok-reference-label c. részben részletesen lesz róla szó. Most elégedj meg annyival, hogy ez egy speciális fájl, amelybe olyan kimeneteket szoktunk átirányítani, amire nincs szükség, a cél csak annyi, hogy az ne jelenjen meg.

6.3. A bemenet átirányítása

A bemenet átirányítása szintén hasznos lehetőség a gyakorlatban, nagy mennyiségű adat gyors bevitelét oldhatod meg, ha a billentyűzet helyett a bemenetet pl. egy fájlra cseréled. Ahhoz, hogy ezt meg tudjam mutatni neked, készítettem egy ketszeres nevű programot, amit a /usr/local/bin könyvtárba másoltam. Ez a pársoros program a standard inputról számokat vár, és minden begépelt szám esetén kiírja annak kétszeresét. Próbáljuk ki!

feri@columbo:~/demo$
3
3*2=6
6
6*2=12
12
12*2=24
^C

Azokat a sorokat, amelyekben egy szám szerepel, én gépeltem be a billentyűzeten, a szorzatot tartalmazó sorok a program válaszai. Az utolsó sorban látható ^C akkor jelent meg, amikor a program futtatását a Ctrl-c megnyomásával megszakítottam.

Tételezzük fel, hogy sok szám kétszeresét kell kiszámolnod, és ezek a számok egy fájlban rendelkezésedre állnak az adatok.txt fájlban:

feri@columbo:~/demo$ cat adatok.txt
3
6
124
12

Végezzük el a kétszeresek kiszámolását minden számra, ami az adatok.txt fájlban van! Ehhez a ketszeres program bemenetét át kell állítani a billentyűzet helyett az adatok.txt fájlra, amihez a < karaktert, majd a forrás fájl nevét kell használni:

feri@columbo:~/demo$ ketszeres <adatok.txt
3*2=6
6*2=12
124*2=248
12*2=24

A parancs eredményként egy pillanat alatt minden szám kétszeresét kiszámolta a program anélkül, hogy egy gombot is le kellett volna nyomni a billentyűzeten. A standard input átállításával a program a adatok.txt sorait úgy dolgozta fel, mint ha azokat normál esetben a billentyűzeten gépeltem volna be.

Megjegyzés

  • Felmerülhet a kérdés, hogy most miért csak a kiszámolt eredmények sorai látszanak. A billentyűzet használata esetén a terminál – úgy mondjuk – visszaechózza a begépelt karaktereket, ami a bemenet átirányítása esetén nem történik meg.

  • A ketszeres program forrása az alábbi, hamarosan te is könnyedén megírod majd te is.

    #!/bin/bash
    while read I ; do
      echo "$I*2="$(expr $I \* 2)
    done
    

6.4. Átirányítás más programra

Az átirányítások legizgalmasabb területe az, amikor a kimenetet egy másik program bemenetére irányítjuk át. Ezzel olyan komplex feladatokat oldhasz meg, amelyekre más rendszerek esetén programokat kellene írnod. Ezzel a következő fejezet foglalkozik, Szűrők címmel.

Ha egy program kimenetét egy másik program bemenetére akarod irányítani, a | karaktert kell használnod. Az alábbi példában e logika mentén használom a ketszeres programot:

feri@columbo:~/demo$ cat adatok.txt | ketszeres
3*2=6
6*2=12
124*2=248
12*2=24

Bár az eredmény ugyanaz, mint amit a bemenet átirányításakor láttál, a működési mechanizmus más. Az első parancs, a cat adatok.txt kimenete 4 sor, amely egyenként a 3, 6, 124 és a 12 számokat tartalmazza. Ez a | karakter miatt nem a standard outputra kerül, hanem az azt követő parancsra, amely példánkban a ketszeres. Ez minden, a bemenetére érkező sort feldolgoz és a kimenetére küldi, ami egyéb rendelkezés híján a terminál képernyője lesz.

Gondolom, nem lepődsz meg, ha azt mondom, nem csak két programot köthetsz így össze, hanem többet is, ennek során az egyik kimenete az azt követő parancs bementére kerül, annak kimenet az őt követő bemenetére és így tovább, valahogy így:

feri@columbo:~/demo$ command1 | command2 | command3

Mivel ez a folyamat arra emlékeztet, mint ha egy csőben áramlanának az adatok, ezt ezt a struktúrát csőnek, angolul pipe-nak nevezik. Ugyanígy a | karakter neve is pipe.

A következő fejezetben olyan programokkal ismerkedünk meg, amelyeket tipikusan ilyen felhasználásra terveztek, az összefoglaló nevük: Szűrők.

6.5. Ellenőrző kérdések

  • Mi a standard input és standard output?

  • Mi az átirányítások módja, és mik a tipikus átirányítási célok?

  • Hogyan lehet a kimenetet átirányítani?

  • Mi a hibacsatorna és hogyan kezelhető?

  • Hogyan lehet a bemenetet átirányítani? Adjon példát a használatára!

  • Hogyan lehet a kimenetet más program bemenetére átirányítani?

6.6. Feladatok

  • Az ls parancs kimenetét irányítsd át a /tmp/lista-<username>.txt fájlba, ahol a <username> helyére helyettesítsd be a bejelentkezési nevedet!

  • Az /etc könyvtár conf-ra végződő fájljainak tartalmát másold össze egyetlen fájlba, a /tmp/lista-<username>.txt-be! Mi történt annak korábbi tartalmával?

  • A /tmp/lista-<username>.txt fájlhoz fűzd hozzá az aktuális dátumot és időt!

  • Hozd létre a /tmp könyvtárat! Az esetleges hibaüzeneteket irányítsd át a hiba.txt fájlba!

  • Hozd létre a /tmp könyvtárat! Gondoskodj róla, hogy az esetleges hibaüzenetek ne jelenjenek meg!