Sok helyen olvashatjuk, hogy a UNIX filozófia mennyire praktikus: sok apró programot össze tudunk kapcsolni, mindegyik kis alkotóelem csak a saját maga feladatát tudja. Aki szereti a LEGO-t, az biztosan könnyen magáévá tudja tenni ezt a filozófiát. :) Ennek ellenére az emberek folyton feature requestekkel bombázzák a fejlesztőket, nem is értem... :-))
Ma a sztenderd kimenettel, bemenettel és a pipe-pal fogunk ismerkedni. Aki a konzoltól alapvetően undorodik, most ugorhat a következő post-ra. :-)
A lényeg tehát, hogy a programoknak, főleg azoknak amelyek bemenetet várnak másik programoktól és/vagy kimenetet biztosítanak további feldolgozásra, szükségük van egy sztenderd felületre, ahol a kommunikációt végezhetik. Ez nyilvánvaló, hiszen egy programozó nem tud felkészülni mindenféle lehetséges esetre - pl. leprogramozza a képernyőre kiírást, de mi van ha nyomtatni kell? Vagy ha hálózaton kell továbbítani? Fájlba menteni?
Sokkal menőbb és egyszerűbb az stdin és stdout használata, így a program csak egy dologra kell felkészüljön, a sztrenderd csatornák pedig átirányíthatóak bármire és bárhova, ezzel ultra rugalmassá téve a dolgot.
Megjegyzés: Az stdin,stdout és stderr Windows-on is létezik; de igyekeznek objektumokkal kiváltani ezt a szerintük elavult technológiát.
Kezdjük az alapoknál! Mondjuk listázzuk az aktuális könyvtárat az ls paranccsal - a sztenderd output alapból a képernyő, ezért oda kapjuk a listát. De az stdout átiányítható egy fájlba a kacsacsőrrel:
ls > fajlok.txt
illetve a pipe jellel egy másik parancsnak átadva a kimenetet, csak azokat listázzuk, amelyek nevében szerepel a "fajl":
ls | grep "fajl"
A grep parancs ugyebár szűri a bemenetet, csak azokat engedi a kimenetre, amit a szabályaiban megadtunk. (Oké, TUDOM hogy az ls *fajl* ugyanazt csinálja mint a fenti példa, de az csak példa!) Az előbb elmentett fájlt is beleirányíthatjuk a grep-be:
grep "fajl" < fajlok.txt
Ez tehát a "visszakacsacsőr", ami beleirányítja a parancsba egy fájl tartalmát, azaz eltéríti az stdin-t.
A pipe tehát igen hasznos, hiszen a lépéseket nem egyesével kell végrehajtanunk és a fájlrendszeren sem keletkeznek esetleg nagy átmeneti fájlok. Nyilván a fentieket egy fullos grafikus editorral is megtehettük volna, sok kattintgatás árán...
Ennyit bemelegítésnek.
diff -y <(ps --cols 80 axo comm) <(ssh bagoj@tavoligep.hu ps --cols 80 axo comm)
"Mint az közismert", összefoghatunk egy több tagból álló parancsot zárójelezéssel. A fenti, szándékosan keményebb példában a diff (összehasonlító) parancsba irányítjuk be külön-külön a helyi (ps --cols 80 axo comm) és egy távoli gép (ssh... stb.) processz listáját, magyarul megnézzük, mi fut a távoli gépen, mi fut a helyi gépen és összevetjük a kettőt. Nyilván ennek akkor van értelme, ha nem számítunk különbségre. (Az ssh, ha nem kulcsosan használjuk, jelszót fog kérni.) Mivel a diff két paramétert vár, szépen beleirányítjuk a ps (process listázó) parancsok kimeneteit.
(A diff használatáért elnézést kérek, tudom hogy a kimenetének megfejtése tapasztalatot igényel, ez meg egy kezdőbbeknek szóló írás, de ez van, nőjetek fel a feladathoz... :-) )
A nagy ijedtségre kicsit könnyebb példák:
1. Könnyen meg tudjuk számolni az aktuális könyvtárban lévő fájlok számát:
ls | wc -l
2. ...nade az aktuális könyvtárban ÉS az alkönyvtárakban is?
find . | wc -l
Az utóbbi két példa magyarázata: Mind az ls, mind a find a megtalált fájlokat egyesével listázza, azaz soronként egy fájl. A wc (word count) a -l (ismét L betű) paraméter hatására megszámolja, hány sort listáztunk.
Nagy kedvencem még az is, amikor egy gyenge gépen szeretnénk letömöríteni egy könyvtárat, majd eljuttatni egy másik gépre. Tegyük fel, hogy nincs helyünk elvégezni a feladatot. Ráadásul ha az a másik gép erősebb, miért ne ott végeztessük a tömörítést?
Legyen hát úgy, hogy nem tárolunk kétszer, hanem egy nekifutással elvégzünk mindent:
tar cf - <könyvtár> | ssh bagoj@távoligép "gzip > könyvtár.tgz"
Egyszerű, nem? A lokális gépen megadjuk a tar-nak, hogy a standard out-ra készítse el az archívumot, ne fájlba - ezt a kötőjellel tesszük meg (tehát a cf utáni "-" nem légypiszok!). A távoli gépen pedig gzip-peljük a bájtfolyamot, és beleirányítjuk egy tar.gz fájlba. Csak ne felejtsük el begépelni az ssh jelszavunkat! (Már persze, ha nem kulcsos az authentikáció).
Hogy a végére maradjon egy praktikus példa is, amivel kapcsolódok a biztonsági mentéshez, amit ugye nem lehet eleget hangsúlyozni. Tömörítsük össze az összes rendszer- és felhasználói mappát, és tegyünk rá jelszóvédelmet a gpg segítségével! Ez egy szimmetrikus kódolás lesz (ezt a gpg -c paramétere biztosítja), tehát nem kell privát kulcsokat tárolni, mindössze meg kell jegyezni jól a jelszót! Így biztonságban tudhatjuk a mentéseinket, senki nem férhet hozzájuk. Természetesen nem muszáj a rendszerfájlokat elmentenünk, csak a számunkra lényeges dolgokat...
tar cpzf - --exclude=/tmp --exclude=/proc --exclude=/lost+found --exclude=/media --exclude=/mnt --exclude=/sys / | gpg --cipher-algo AES256 -c -z 0 -o mentes.tar.gpg
...illetőleg így tudjuk kicsomagolni:
gpg -d mentes.tar.gpg | tar xzvp -C /
Ha csak a saját könyvtárunkban csomagolunk valamit ki-be, akkor nem kell ez a nagy herce-hurca, csak
tar cpzf - <könyvtár> | gpg --cipher-algo AES256 -c -z 0 -o mentes.tar.gpg
és
gpg -d mentes.tar.gpg | tar xzvp
Aranyos, nem?
Mai napi bónusz
A bash parancssorban otthonosabban mozoghatunk az alábbi billentyűkombinációkkal:
- Ctrl + a => Az éppen begépelt parancs elejére ugrik
- Ctrl + e => Az éppen begépelt parancs végére ugrik
- Ctrl + u => A kurzor előtti tartalom vágólapra másolása (ez nem ugyanaz, mint a Ctrl + C, hanem egy másik vágólap!)
- Ctrl + k => A kurzor utáni tartalom vágólapra
- Ctrl + y => Az előbb elmentett tartalom visszamásolása
- Ctrl + t => A kurzor előtti két karakter felcserélése (pl. ezzel a sor elejéről a végére tudunk "buborékoltatni" egy betűt. Az értelmét ne keressük
- Ctrl + w => A kurzortól balra eső szó törlése
- Ctrl + l => A képernyő törlése, igen hasznos (ez itt kis L-betű, nem nagy i!)
- Ctrl + z => Ha épp fut egy parancs, felfüggeszthetjük a futását. Ezután az fg paranccsal tudjuk visszahozni. Ezt majd kifejtem részletesebben...