Text, roury a filtry

pipe, grep, sed, awk, sort, přesměrování.

V Linuxu je text král a nejsilnější trik celého systému je zdánlivě banální: výstup jednoho programu pošleš jako vstup druhého. Místo jednoho obřího nástroje, který umí všechno, máš hromadu maličkých, z nichž každý dělá jednu věc dobře — a ty je skládáš dohromady jako díly na pásové lince. Tomuhle skládání se říká roura (|) a je to srdce takzvané unixové filozofie. Až ti to „cvakne", přestaneš hledat speciální program na každý problém a začneš si nástroje řetězit.


Pár pojmů na úvod

  • stdin (standardní vstup, kanál 0) = odkud program čte data. Klávesnice, soubor, nebo výstup předchozího příkazu v rouře.
  • stdout (standardní výstup, kanál 1) = kam program píše svůj normální výsledek. Ve výchozím stavu terminál, ale dá se přesměrovat do souboru nebo do dalšího příkazu.
  • stderr (chybový výstup, kanál 2) = kam program píše chyby a hlášky. Je zvlášť od stdout, aby ti chyby nezaneřádily užitečný výstup, když ho posíláš dál rourou.
  • Přesměrování = přesměruješ proud jinam než na terminál — do souboru (>, >>), ze souboru (<), nebo chyby stranou (2>).
  • Roura (pipe, |) = spojka, která bere stdout levého příkazu a strká ho na stdin pravého.
  • Filtr = program, který čte ze stdin, něco s tím udělá a píše na stdout. Přesně ty se řetězí do rour — grep, sort, uniq, wc, cut, tr, sed, awk.

Tři proudy: vstup, výstup a chyby zvlášť

Každý program má od startu tři „trubky" napojené do světa. Představ si je jako tři barevné hadice:

  • 0 — stdin: čtení dovnitř (co program dostává).
  • 1 — stdout: normální výstup ven (co program „říká").
  • 2 — stderr: chyby ven (co program „nadává").

Proč jsou výstup a chyby oddělené? Protože chceš umět poslat dál jen užitečná data, ale chybové hlášky vidět na obrazovce. Kdyby byly smíchané, ls | grep neco by ti do výsledku občas propašovalo i hlášku „soubor neexistuje" a rozbilo další zpracování.

# stdout jde do souboru, ale chyba se stejně vypíše na terminál
ls /existuje /neexistuje > vypis.txt
# → do vypis.txt se uloží nalezené, hláška o chybějícím souboru zůstane na obrazovce (stderr)

Přesměrování — kam tečou data

Přesměrování řekne shellu: „neposílej tenhle proud na terminál, ale sem".

echo "ahoj" > soubor.txt      # stdout DO souboru — PŘEPÍŠE celý obsah!
echo "další" >> soubor.txt     # stdout DO souboru — PŘIDÁ na konec (nepřepíše)
wc -l < soubor.txt             # stdin ZE souboru (soubor krmí příkaz)
příkaz 2> chyby.log            # stderr do souboru (chyby stranou)
příkaz &> vse.log              # stdout I stderr do jednoho souboru
příkaz > vystup.log 2>&1       # totéž klasicky: "2 pošli tam, kam jde 1"
příkaz 2> /dev/null            # chyby zahoď úplně (/dev/null = černá díra)

⚠️ > je nemilosrdné. Neptá se, nezálohuje — okamžitě vymaže obsah cílového souboru a napíše nový. >> naopak jen přidává. Nauč se ten rozdíl dřív, než si > omylem přepíšeš důležitý soubor.

Zápis 2>&1 čti jako „nasměruj kanál 2 tam, kam už míří kanál 1". Proto záleží na pořadí: > soubor 2>&1 funguje (nejdřív 1 → soubor, pak 2 → za 1), kdežto 2>&1 > soubor pošle chyby ještě na terminál, protože v tu chvíli 1 ještě míří na obrazovku.


Roura | — pásová linka z malých nástrojů

Roura je ta nejdůležitější věc v celé kapitole. Vezme stdout levého příkazu a napojí ho přímo na stdin pravého — bez ukládání do souboru, rovnou z paměti do paměti.

cat pristup.log | grep "ERROR"        # vezmi log a nech jen řádky s ERROR

Tady je celá unixová filozofie: cat umí jen vypsat soubor, grep umí jen filtrovat řádky. Ani jeden neumí to druhé — a to je záměr. Malé nástroje, každý dělá jednu věc dobře, a rourou z nich poskládáš přesně to, co potřebuješ. Je to jako pásová linka: každý stroj udělá jeden úkon a pošle polotovar dál.

Data tečou zleva doprava, každý díl je filtr — čte ze stdin, něco udělá, píše na stdout. Roura mezi nimi je ta trubka, co je propojuje.


Filtry, které použiješ pořád

Tohle je tvoje základní bedna nářadí. Každý z nich je filtr — dá se řetězit s ostatními.

grep — najdi řádky, které odpovídají vzoru.

grep "chyba" log.txt          # řádky obsahující "chyba"
grep -i "chyba" log.txt       # -i = ignoruj velikost písmen (Chyba, CHYBA…)
grep -n "chyba" log.txt       # -n = přidej čísla řádků
grep -v "chyba" log.txt       # -v = obrácení: řádky, které vzor NEobsahují
grep -r "TODO" .              # -r = rekurzivně projdi celý strom adresářů

sort — seřaď řádky. uniq — zahoď opakující se sousední řádky.

sort jmena.txt                # abecedně
sort -n cisla.txt             # -n = číselně (jinak "10" < "2"!)
sort -rn cisla.txt            # -r = obráceně (od největšího)
sort jmena.txt | uniq         # unikátní řádky (uniq VYŽADUJE seřazený vstup!)
sort jmena.txt | uniq -c      # -c = spočítej výskyty každého řádku

wc — počítání. cut — vyřízni sloupce. tr — nahraď/smaž znaky.

wc -l soubor.txt              # -l = počet řádků (nejčastější použití)
cut -d':' -f1 /etc/passwd     # -d = oddělovač, -f1 = první sloupec (uživatelská jména)
echo "Ahoj Svete" | tr 'a-z' 'A-Z'   # převod na velká písmena → AHOJ SVETE
echo "a,b,c" | tr ',' '\n'    # nahraď čárky novými řádky

sed a awk — ochutnávka dvou mocností

Až vyrosteš z grep/cut, čekají tě dva „těžkokalibrové" filtry. Teď jen ať víš, že existují.

sed — stream editor, hlavně na hledání a nahrazování textu:

sed 's/staré/nové/g' soubor.txt      # nahraď "staré" za "nové" — g = na každém výskytu v řádku
cat log.txt | sed 's/ERROR/CHYBA/g'  # v proudu přejmenuj ERROR na CHYBA

Čti s/co/čím/g jako substitute (nahraď) — co za čím, g = globálně (všechny výskyty na řádku, ne jen první).

awk — nástroj na sloupce a tabulky. Umí toho hodně, ale nejčastěji ho uvidíš takhle:

awk '{print $1}' soubor.txt          # vytiskni první sloupec každého řádku
awk '{print $1, $3}' soubor.txt       # první a třetí sloupec
ps aux | awk '{print $2, $11}'        # z výpisu procesů jen PID a název příkazu

$1, $2… jsou sloupce (rozdělené mezerami), $0 je celý řádek. Zatím ber sed a awk jako pozvánku — až tě „malé filtry" přestanou stačit, vrátíš se k nim.


Praktická komba, co uvidíš každý den

Síla roury je v kombinaci. Pár klasik, které stojí za to umět nazpaměť:

# Kolik chyb je v logu?
cat aplikace.log | grep "ERROR" | wc -l

# Žebříček nejčastějších hodnot (top-fráze zdola nahoru)
cat pristup.log | cut -d' ' -f1 | sort | uniq -c | sort -rn

# Které IP adresy nás bušily nejvíc? (prvních 10)
cat pristup.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -10

To druhé kombo je klasika, kterou si zapamatuj: sort | uniq -c | sort -rn = „spočítej výskyty a seřaď od nejčastějšího". Nejdřív sort (aby uniq viděl stejné řádky vedle sebe), pak uniq -c (spočítá), pak sort -rn (seřadí číselně odshora). Přesně tak se dělá žebříček četností — na cokoli od IP adres po slova v textu.


Failure modes — časté omyly začátečníků

  • > ti přepíše soubor bez varování. echo "x" > dulezity.txt vymaže starý obsah. Chceš-li přidat, je to >>. Když si nejsi jistý, nejdřív >>, přepsat můžeš vždycky.
  • cmd < soubor > tentýž.soubor = katastrofa. Shell nejdřív vyprázdní cílový soubor kvůli >, teprve pak spustí příkaz — takže čteš z prázdna a přijdeš o data. Zapisuj do jiného souboru, pak přejmenuj.
  • uniq bez sort napřed. uniq zahazuje jen sousední duplicity. Bez předchozího sort ti nechá rozházené kopie a budeš se divit, proč tam pořád jsou. Pravidlo: uniq skoro vždy až po sort.
  • Zapomenuté uvozovky u vzoru s mezerou. grep chyba disku log.txt shell rozdělí — grep hledá chyba v souborech disku a log.txt. Chceš grep "chyba disku" log.txt. Vzor s mezerou vždy do uvozovek.
  • Chyby smíchané s daty. Když příkaz | dalsi nefunguje divně, může za to stderr. Přesměruj chyby (2> /dev/null nebo 2> chyby.log), ať vidíš jen čistý datový proud.

🛠️ Cvičení

  1. Přepiš vs. přidej. Vytvoř soubor přes echo "první řádek" > pokus.txt, pak zkus jednou > a jednou >> s druhým textem a podívej se přes cat pokus.txt, co se stalo. Vysvětli rozdíl vlastními slovy a řekni, kdy je > nebezpečné.
  2. Postav rouru na počítání. Máš textový soubor s řádky. Napiš rouru, která spočítá, kolik řádků obsahuje slovo error bez ohledu na velikost písmen. (Nápověda: grep -i, wc -l.)
  3. Žebříček četností. Ze souboru, kde je na každém řádku jedno slovo (nebo z prvního sloupce logu), vyrob top 5 nejčastějších hodnot i s počty. Poskládej sort, uniq -c, sort -rn, head.
  4. Sloupce a chyby stranou. Ze souboru /etc/passwd (sloupce oddělené :) vytáhni jen uživatelská jména (první sloupec) a seřaď je abecedně. Zkus přitom nějaký příkaz, který částečně selže, a jeho chyby pošli do /dev/null.
  5. stderr vs stdout. Spusť ls existujici_slozka neexistujici_slozka a rozděl výstup tak, aby normální výpis šel do out.txt a chyby do err.txt. Ověř cat, že v každém souboru je to správné.
Náčrt řešení — rozbal, až si cvičení zkusíš sám
  1. Přepiš vs. přidejecho "druhý" > pokus.txt smaže „první řádek" a nechá tam jen „druhý". echo "druhý" >> pokus.txt nechá oba řádky. > je nebezpečné, protože maže okamžitě a bez ptaní — stačí omyl a přijdeš o obsah. Pozor: > vyprázdní soubor ještě před během příkazu, takže cmd < f > f zničí f.
  2. Počítání řádkůgrep -i "error" soubor.txt | wc -l. grep -i najde error/Error/ERROR, wc -l spočítá řádky, které prošly. Pozor: wc -l počítá řádky, ne výskyty — dva error na jednom řádku se počítají jako jeden. Na výskyty by byl potřeba grep -o napřed.
  3. Žebříček četnostísort slova.txt | uniq -c | sort -rn | head -5. Nejdřív sort (aby stejná slova byla u sebe), uniq -c je spočítá, sort -rn seřadí číselně odshora, head -5 vezme prvních pět. Pozor: uniq musí jít až po sort, jinak spočítá jen sousední duplicity a výsledek bude nesmysl.
  4. Sloupcecut -d':' -f1 /etc/passwd | sort. -d':' říká, že oddělovač je dvojtečka, -f1 bere první pole (jméno), sort seřadí. Chyby jiného příkazu utišíš přidáním 2> /dev/null. Pozor: cut počítá pole podle jednoho znaku oddělovače — víc mezer za sebou by dělalo prázdná pole (na to je lepší awk).
  5. stderr vs stdoutls existujici_slozka neexistujici_slozka > out.txt 2> err.txt. > out.txt chytí normální výpis (kanál 1), 2> err.txt chytí chybu o chybějící složce (kanál 2). Pozor: pořadí 2>&1 je záludné — 2>&1 > out.txt by chyby poslalo ještě na terminál, protože 1 v tu chvíli míří na obrazovku.

🧠 Otázky & odpovědi

K čemu je roura | a jak funguje?

Roura vezme stdout (normální výstup) levého příkazu a napojí ho přímo na stdin (vstup) pravého příkazu — data tečou z paměti do paměti, bez ukládání do souboru. Díky tomu řetězíš malé nástroje do delších pipeline: cat log | grep ERROR | wc -l = vypiš log, nech jen chybové řádky, spočítej je. Je to jádro unixové filozofie „malé nástroje, každý dělá jednu věc dobře" — místo jednoho obřího programu skládáš mnoho jednoúčelových jako díly na pásové lince.

Jaký je rozdíl mezi > a >>?

> přesměruje výstup do souboru a přitom ho přepíše — starý obsah okamžitě a bez varování zmizí. >> výstup do souboru jen přidá na konec, původní obsah nechá být. Praktický důsledek: echo x > f smaže f a nechá tam jen „x"; echo x >> f nechá, co bylo, a přidá řádek. Nejčastější začátečnická katastrofa je omylem přepsat důležitý soubor přes >. Ještě zákeřnější je cmd < f > f — shell nejdřív vyprázdní f a teprve pak čte, takže přijdeš o data.

Proč jsou stdout a stderr oddělené proudy?

Aby se ti chybové hlášky nemíchaly s užitečnými daty. Normální výstup jde na kanál 1 (stdout), chyby na kanál 2 (stderr). Když posíláš výstup dál rourou (cmd | dalsi), teče tam jen stdout — chyby zůstanou viditelné na terminálu a nerozbijí ti další zpracování. Můžeš s nimi nakládat zvlášť: 2> chyby.log chyby uložit, 2> /dev/null úplně zahodit, 2>&1 je spojit s výstupem. Kdyby byly v jednom proudu, každá hláška „soubor nenalezen" by ti zaneřádila data.

Proč se uniq skoro vždy dává až po sort?

Protože uniq zahazuje jen sousední stejné řádky — nehledá duplicity po celém souboru, jen porovnává každý řádek s tím předchozím. Když jsou stejné hodnoty rozházené po souboru, uniq je nechá být. sort je proto srovná vedle sebe a teprve pak uniq funguje správně. Odtud pochází klasické kombo sort | uniq -c | sort -rn na žebříček četností: seřaď, spočítej výskyty (-c), a znovu seřaď číselně odshora podle počtu.

K čemu jsou grep, cut, sort, wc a kdy který?

Jsou to základní filtry — čtou ze stdin, něco udělají, píšou na stdout. grep hledá řádky podle vzoru (-i ignoruj velikost, -v obrať, -r rekurzivně, -n čísla řádků). cut vyřízne sloupce (-d oddělovač, -f číslo pole) — na text s pevnými sloupci jako /etc/passwd. sort seřadí (-n číselně, -r obráceně). wc -l spočítá řádky. Poskládané rourou pokryjí většinu každodenní práce s textem; na složitější úpravy pak přijdou sed (nahrazování) a awk (sloupce a tabulky).