Text, roury a filtry

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

Co se naučíš: Naučíš se skládat malé nástroje do řetězu a zpracovat text způsobem, na který by jinde byl potřeba program.

15 min čtení + cvičeníNavazuje na:📁 Základní příkazy

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řidej, echo "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. Sloupce, cut -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 stdout, ls 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).