Pokud chceme zpracovávat celý soubor, řádku po řádce, můžeme použít následující jednoduchý cyklus s přesměrováním standardního vstupu.
#!/bin/sh while IFS=" :=\t" read name value do echo "$name='$value'" … done < /cesta/k/souboru
Uvedený příklad nám poslouží jen v jednodušších případech. Ve složitějších narazíme na omezení přesměrování standardního vstupu. Pokud potřebujeme načítat soubor v několika příkazech read a ukládat si zjištěné informace do proměnných, s uvedeným mechanismem nevystačíme. Problém na který narazíme je problémem vnořených shellů. Aby všechny příkazy read četly z jednoho souboru, musíme přesměrování vstupu učinit uzavřením celého bloku příkazů do vnořeného shellu pomocí kulatých závorek. Vstupní soubor pak na konci přesměrujeme do tohoto bloku. Uvnitř vnořeného shellu ale není možno modifikovat proměnné vně. Takže pokud budeme provádět například vyhledávání maxima či výpočet součtu hodnot. S následující konstrukcí neuspějeme.
… maximum=0 ( … read line … while … read name value … … maximum=… done ) < $IFILE # maximum je zde 0
Řešením této situace je využití možnosti příkazu read načítat vstupní větu z jiného deskriptoru než standardního vstupu. Takto můžeme konstruovat mnohem složitější algoritmy kdy čteme z více souborů najednou a čtená data kombinujeme. Nejdříve tedy jak bude vypadat náš jednoduchý příklad.
exec 3</cesta/k/souboru while IFS=" :=\t" read -u3 name value; do echo "$name='$value'" … done exec 3<&-
První řádek otevírá soubor v deskriptoru 3. Volba -u3
říká read že má číst z deskriptoru 3 a nikoliv ze standardního vstupu (deskriptor 0). Poslední příkaz uzavírá soubor v deskriptoru 3.
Jště uvedu ukázkový příklad čtení konfiguračního souboru.
CONF=/cesta/k/souboru exec 3<$CONF while read -u3 line; do if [[ "$line" =~ "^#" ]]; then continue; fi #Ignorujeme komentáře if [[ "$line" =~ "^[ \t]*$" ]]; then continue; fi #Ignorujeme prázdné řádky … done exec 3<&-
Dříve jsem nevěděl o možnosti zadávat v příkazu read číslo deskriptoru, a tak jsem používal následující vzor. Na začátku si uložím stdin, otevřu v stdin soubor a na konci zase obnovím stdin. Toto dělají dva příkazy exec.
#!/bin/shIFILE
=/etc/passwd
exec 3<&0 <$IFILE
whileIFS
=":" readlogin
hash
uid
gid
gecos
home
shell
; do echo "$login
$shell
" done exec 0<&3 3<&-