Zreťazenie

**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. 

## Príklady
### Jednoduchý príklad

```bash
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
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)

```bash
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 **<tt>[[CURL|curl]]</tt>** HTML obsah webovej stránky (na niektorých systémoch by bolo možné použiť i wget).
* Tak **<tt>[[sed]]</tt>** odstráni z obsahu stránky všetky znaky, ktoré nie sú medzerami alebo písmenami a vymení ich za medzery.
* Potom **<tt>[[tr (program)|tr]]</tt>** 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 **<tt>[[grep]]</tt>** vyberie len tie riadky, ktoré obsahujú aspoň jedno malé písmeno abecedy (odstráni všetky prázdne riadky).
* Následne **<tt>[[Sort (Unix)|sort]]</tt>** usporiada zoznam 'slov' podľa abecedného poradia, pričom prepínač -u odstráni duplikáty.
* Napokon **<tt>[[comm (Unix)|comm]]</tt>** 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.

## Zreťazenia v [[command line interface|rozhraniach príkazových riadkov]]
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
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.

### Pipemill
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:

```bash
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

```bash
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:

```bash
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í
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|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ťazenie|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
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.

## Pozri aj
* Zoznam viacerých príkazov pre Zreťazenie
Kategória:Technológie operačných systémov
Kategória:Unix