Preskočiť na obsah

Zreťazenie

z Wikipédie, slobodnej encyklopédie

Zreťazenie alebo pipeline je v Unix-ových operačných systémoch pôvodne softvérové zreťazenie: množina procesov zreťazených svojimi štandardnými prúdmi tak, že výstup každého procesu (stdout) slúži ako vstup (stdin) pre ďalší proces. Každé takéto spojenie je uskutočnené prostredníctvom anonymného zreťazenia. Takto sa zvyknú používať filtrovacie programy. Tento princíp bol vynájdený Douglasom McIlroyom pre Unixové shell-y a v angličtine (pipeline = potrubie) a pomenovaný bol na základe analógie s fyzickým potrubím.

Jednoduchý príklad

[upraviť | upraviť zdroj]
ls -l | less

V tomto príklade je ls unix-ový príkaz na výpis obsahu adresára a less je interaktívny stránkovač textov s možnosťami vyhľadávania. Zreťazenie umožňuje používateľovi ľubovoľne prechádzať výpisom adresára, ktorý sa nemusí zmestiť na obrazovku.

Rúry končiace príkazom less (alebo more, podobný stránkovač textov) patria medzi najčastejšie využívané. Umožňujú používateľovi prechádzať aj veľmi veľké (či nekonečné) množstvo textu, ktorý by sa inak dostal nad vrchný riadok terminálu teda sa stratil. Inými slovami takéto zreťazenia uľahčujú prácu programátorom, ktorý sa už nemusia starať o implementácia stránkovačov vo svojich aplikáciach: jednoducho môžu prepojiť výstup rúrou prostredníctvom programu less alebo predpokladať, že v prípade núdze tak urobí používateľ.

Náročnejší príklad

[upraviť | upraviť zdroj]

Nižšie je príklad zreťazenia, ktoré umožňuje akúsi formu kontroly pravopisu webovej stránky na tejto URL adrese. Nasleduje vysvetlenie toho ako to funguje. (Niektoré systémy využívajú /usr/share/dict/words)

curl "http://en.wikipedia.org/wiki/Pipeline_(Unix)" | \
sed 's/[^a-zA-Z ]/ /g' | \
tr 'A-Z ' 'a-z\n' | \
grep '[a-z]' | \
sort -u | \
comm -23 - /usr/dict/words
  • Najprv získa curl HTML obsah webovej stránky (na niektorých systémoch by bolo možné použiť i wget).
  • Tak sed odstráni z obsahu stránky všetky znaky, ktoré nie sú medzerami alebo písmenami a vymení ich za medzery.
  • Potom tr zmení všetky veľké písmen na malé a zmení medzery medzi slovami v riadkoch na oddeľovače nových riadkov (každé takto vzniknuté 'slovo' sa bude teraz nachádzať na samostatnom riadku).
  • Ďalej grep vyberie len tie riadky, ktoré obsahujú aspoň jedno malé písmeno abecedy (odstráni všetky prázdne riadky).
  • Následne sort usporiada zoznam 'slov' podľa abecedného poradia, pričom prepínač -u odstráni duplikáty.
  • Napokon comm nájde spoločné riadky medzi dvoma súbormi, pričom -23 odignoruje riadky, ktoré sa nachádzajú len v druhom súbore a tie ktoré sa nachádzajú v oboch súboroch, čiže ponechá len tie slová, ktoré sa našli len v prvom zadanom súbore. Znak - namiesto mena súboru spôsobí, že comm využije svoj štandardný vstup (v tomto prípade z rúry). Takto vytvoríme zoznam "slov" (riadkov), ktoré sa nenašli v slovníkovom súbore /usr/dict/words.
  • Špeciálny znak "|" dáva povel operačnému systému, aby prepojil výstup z predchádzajúceho príkazu na riadku na vstup nasledujúceho príkazu na riadku. Čiže výstup príkazu curl sa stane vstupom pre príkaz sed.
  • Symbol "\" sa používa na zaradenie všetkých šiestich riadkov do jedného príkazového riadku.

Väčšina unixových shell-ov používa na tvorbu zreťazení špeciálne syntaktické konštrukcie. Často stačí písať filtrovacie príkazy za sebou oddelené ASCII znakom hrizontálnej čiary "|" (ktorý je práve z tohto dôvodu používateľmi Unix-u často nazývaný "znak rúry"). Shell spustí tieto procesy a zariadi, aby vzniklo potrebné prepojenie medzi ich štandardnými prúdmi (vrátane zabezpečenia buffer-a istej veľkosti).

Chybový výstup

[upraviť | upraviť zdroj]

Obyčajne štandardné chybové výstupy ("stderr") procesov v zreťazení cezeň neprenášajú; namiesto toho sa spoja a presmerujú do konzoly. Okrem toho mnohé shelly majú rozšírenú syntax o prvky na zmenu tohto správania. Napríklad v shelli csh použitím "|&" namiesto "| " značí, že štandardný chybový výstup sa má tiež spojiť so štandardným výstupom a prepojiť na vstup ďalšieho procesu. Bourne shell môže tiež pripojiť štandardný chybový výstup použitím 2>&1 alebo ho tiež presmerovať do iného súboru.

V najčastejšie používaných jednoduchých zreťazeniach shell spája sériu podprocesov, v ktorých vykonáva externé príkazy. Teda shell sám o sebe priamo dáta v zreťazení nespracuváva.

Je však možné, aby spracovanie dát vykonával samotný shell. Táto konštrukcia vo všeobecnosti vyzerá asi takto:

príkaz | while read var1 var2 ...; do
   # spracuje každý riadok pomocou z neho získaných premenných $var1, $var2, atď.
   done

... a vraví sa jej "pipemill" (zreťazovací mlyn, keďže while "premelie" výstup z počiatočného príkazu)

Príklad Pipemill-u

[upraviť | upraviť zdroj]
find / /usr /var -mount -user niekto -printf "%m %p\n" | while read mód meno_súboru; do
    chown $NOVÝ_VLASTNÍK "$meno_súboru"
    chmod $MÓD "$meno_súboru"
    done

(V tomto príklade sa budú prechádzať súborové stromy pričom sa zmení vlastník každého súboru, no zachovajú sa všetky prístupové práva vrátane tých, ktoré sa často použitím mnohých verzií príkazu chown stratia.)

Existuje viacero variácií konštrukcie pipemill-u, vrátane tejto:

ps lax | { read x; while read x vlastník pid rodič x x x x x status x; do
   [ "$vlastník"="niekto" -a "$status"="Z" ] && kill "$rodič"
   done
   }

(Tento príkaz ukončí rodičovské procesy zombie procesov vlastnených alebo vytvorených užívateľom "niekto".)

Tuto je slučka while uzavretá v skupine príkazov (zložené zátvorky), ktorej predchádza príkaz read, ktorý "zahodí" prvý riadok výstupu z príkazu ps. (SAmozrejme v tomto konkrétnom príklade by bolo spracovanie prvého riadku bez následkov, lebo nesplní podmienku testu "$vlastník"= ). Všimnite si, že premennú "x" používame len ako miesto na "odhadzovanie" nepodstatných informácií z každého riadku.

Pojem "pipemill" by sa dal charakterizovať týmto opisom: príkaz alebo viacero príkazov vkladá dáta do zreťazenia pričom ich shell v slučke while číta a spracúva.

Programové vytváranie zreťazení

[upraviť | upraviť zdroj]

Zreťazenia možno vytvárať v rámci programovej kontroly. Systémové volanie pipe() požiada operačný systém, aby vytvoril novú anonymnú rúru. Toto spôsobí, že v procese sa otvoria dva nové popisovače súborov(file descriptor-y): jedna strana zreťazenia určená len na čítanie a druhá strana určená len na zapisovanie. Tieto "konce" zreťazenia sa javia ako bežné anonymné popisovače súborov s tou výnimkou, že nie je možné v nich vyhľadávať.

Aby sa zabránilo uviaznutiu a problémom spojeným s paralelizmom, proces s jedným či viacerými novými zreťazeniami následne zväčša zavolá fork(), aby sa vytvorili nové procesy. Nový proces potom zatvorí koniec(či konce) zreťazenia, ktorý nebude používať kým nevyprodukuje alebo nezíska nejaké dáta. Namiesto toho môže proces vytvoriť nové vlákno a zreťazenie využije na komunikáciu s ním.

Pomenované zreťazenia môžu byť vytvorené pomocou mkfifo() alebo mknod() a potom ponúknuté ako vstupný alebo výstupný súbor pre vyvolané programy. Tento typ zreťazenia umožňuje vytvorenie viac cestných zreťazení, ktoré sú obzvlášť efektívne keď sa skombinujú s presmerovaním štandardného chybového výstupu alebo s príkazom tee.

Implementácia

[upraviť | upraviť zdroj]

Vo väčšine Unix-ových systémov sa spúšťajú všetky procesy v zreťazení v jednom okamihu už s prepojenými vstupno-výstupnými prúdmi, plánované spolu s ostatnými procesmi bežiacimi v systéme.