Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Substituce příkazů a procesů

Substituce příkazů

Substituci příkazů jsme popsali v kapitole Podshell: výraz $(command) se nahradí standardním výstupem příkazu command. Zde doplníme několik podrobností, které z pohledu expanzí stojí za zmínku.

Koncové znaky nového řádku se odstraňují. Shell z výstupu odřízne všechny znaky nového řádku na konci, jinak by se s výsledkem obtížně pracovalo.

> echo "[$(echo ahoj)]"
[ahoj]

Vnitřní znaky nového řádku ovšem zůstávají, a bez uvozovek je pak rozdělí dělení slov.

> touch a.txt b.txt c.txt
> for f in $(ls); do echo "[${f}]"; done
[a.txt]
[b.txt]
[c.txt]

> for f in "$(ls)"; do echo "[${f}]"; done
[a.txt
b.txt
c.txt]

Substituce lze vnořovat. To je hlavní praktický důvod, proč dáváme přednost $( ) před zpětnými apostrofy: u zpětných apostrofů bychom museli vnitřní výskyty escapovat.

> echo $(basename $(dirname /a/b/c.txt))
b

Výsledek prochází dělením slov a expanzí jmen souborů. Platí tedy stejné varování jako u proměnných: obsahuje-li výstup mezery nebo žolíky, bez uvozovek se rozpadne nebo změní.

> touch "soubor s mezerami.txt"
> for f in $(ls); do echo "[${f}]"; done
[soubor]
[s]
[mezerami.txt]

Toto je zároveň důvod, proč se výstup ls nemá zpracovávat cyklem; místo toho použijeme expanzi jmen souborů:

for f in *
do
    echo "[${f}]"
done

Substituce procesů

Substituce procesů je rozšíření Bashe, které umožňuje předat výstup příkazu tam, kde jiný příkaz očekává jméno souboru.

<(command)     # vystup command je dostupny jako soubor ke cteni
>(command)     # zapis do "souboru" jde na vstup command

Shell příkaz spustí a výraz nahradí jménem souboru, obvykle cestou k pojmenované rouře v /dev/fd.

> echo <(ls)
/dev/fd/63

Typickým použitím je porovnání výstupů dvou příkazů. Bez substituce procesů bychom museli vytvářet dočasné soubory.

> diff <(sort soubor1.txt) <(sort soubor2.txt)
> diff <(ls adresar1) <(ls adresar2)

Substituce procesů a cykly while read

V kapitole Vstup pomocí read jsou dvě varianty čtení souboru po řádcích. Varianta s rourou má nepříjemnou vlastnost, kterou teď můžeme vysvětlit: každá část roury běží v podshellu, takže proměnné nastavené v těle cyklu po jeho skončení zaniknou.

# NEFUNGUJE: po cyklu je count opet 1
count=1
cat soubor.txt | while read line
do
    count=$(( count + 1 ))
done
echo "precteno $(( count - 1 )) radku"

Řešením je přesměrování ze souboru, které jsme už použili, nebo — potřebujeme-li zpracovat výstup příkazu — právě substituce procesů:

count=1
while read line
do
    count=$(( count + 1 ))
done < <(grep 'vzor' soubor.txt)
echo "precteno $(( count - 1 )) radku"

Mezera mezi < a <( je podstatná: první znak je přesměrování standardního vstupu, <( … ) je substituce procesů. Bez mezery by shell četl výraz jako přesměrování <<.