přejít na obsah přejít na navigaci

Linux E X P R E S, Bash 14: Interaktivní skripty: read

Bash 14: Interaktivní skripty: read

Možná máte ze skriptů prezentovaných v tomto seriálu divný pocit, jako by to nebyly plnohodnotné programy, jako by jim něco chybělo. Abstrahujeme-li od grafického rozhraní, zjistíme, že schází jakákoli komunikace s uživatelem. Ano, všechny zde dosud prezentované skripty byly neinteraktivní. Dnes tento nedostatek odstraníme seznámením se s příkazem read. Bohdan Milar .


Řádky a slova

Nejprve si prosvištíme trochu teorie. Řádek je v podání Bashe sekvence znaků zakončená znakem (klávesou) [Return] ([Enter]). Slova jsou části řádku oddělené speciálními znaky. Tyto znaky se nazývají vstupní oddělovače polí (Input Field Separator - IFS) a jejich seznam je uchováván v proměnné IFS.

Pokud si ovšem zkusíte vypsat její obsah (echo $IFS), pravděpodobně nic neuvidíte. To proto, že výchozím oddělovačem slov je mezera a její vypsání na prázdný řádek budí stále dojem prázdného řádku. Zkuste ji tedy obklíčit třeba písmeny a (echo a${IFS}a).

Příkaz read

Úkolem read je číst standardní vstup a takto získanými daty naplňovat zadané proměnné. Přesněji řečeno přečte vždy jeden řádek vstupu, rozdělí jej na slova a ta postupně přiřadí zadaným proměnným.

Nejjednodušším zápisem je samotný příkaz read. V tomto případě je celý řádek načten do proměnné REPLY. Pokud chceme vstupem naplňovat konkrétní proměnnou, zadáme jednoduše její jméno za read, např. read login naplní proměnnou login zadaným řetězcem. Pro naplnění dvou proměnných by vypadal zápis takto: read jmeno prijmeni.

Pokud je na vstupu zadáno více slov, než je počet proměnných, dosadí se do poslední z nich všechna zbývající slova včetně oddělovačů. Pokud je naopak v řádku slov méně, jsou zbývající proměnné naplněny prázdným řetězcem. Read přichází také s několika přepínači. Vybíráme z nich:

-a pole - místo do proměnných ukládá read načtené hodnoty do pole zadaného jména (počínaje hodnotou [0]) - viz 5. díl;

-n x - nečte řádek, ale jen x znaků, což se hodí pro zadávání hodnot přesně dané délky nebo prostě pro čekání na stisk klávesy (read -n 1);

-s - způsobí, že zadávané znaky nebudou zobrazovány, čehož lze využít např. při zadávání hesla nebo jiných důvěrných údajů;

-t sekundy - read bude čekat na vstup z klávesnice jen stanovený počet sekund.



Použití ve skriptech

Čekání na stisk klávesy:

while true; do
echo "Stiskněte klávesu"
read -n 1
echo -n "Právě je "; date
done

Zadávání jména a hesla:

echo -n "Jméno: "; read jmeno
echo -n "Heslo: "; read -s heslo
echo "Heslo pro $jmeno zadáno."

Příkaz read může pracovat i s jinými vstupy než klávesnice. Za upozornění však stojí, že při použití konstrukce roura nepracuje tak, jak většina uživatelů očekává (viz 6. díl).

Místo

echo "aa bb" | read a b ; echo $a $b

je třeba použít

echo "aa bb" | ( read a b ; echo $a $b )

Častější je však použití pro načítání víceřádkových souborů. Ukažme si, jak ze souboru /etc/fstab (seznam přípojných bodů) vybrat jen údaje o discích a přípojných bodech:

grep -v "^#" /etc/fstab | while read disk bod zbytek
do echo "$disk na $bod"
done

V prvním řádku jsme odfiltrovali řádky začínající křížkem a výsledek jsme předali smyčce while, která bude probíhat tak dlouho, dokud ji bude grep zásobovat vyhovujícími řádky z /etc/fstab. V každém průběhu smyčkou uloží read první pole zpracovávaného řádku do proměnné disk, druhé do bod a zbytek řádku do zbytek. Zbytek smyčky je triviální.

Závěr

Takže konečně máme nástroj, kterým můžeme zapojit uživatele do hry, tedy přesněji řečeno do práce s našimi skripty. Prakticky si to předvedeme hned příště s příkazem case.

Nahoru

Odkazy

Příspěvky

Bash, 14. díl
bashovy zacatecnik 4. 06. 2010, 01:29:51
Odpovědět  Odkaz 
K poslednímu příkladu:
Jak to udělat, aby data načtená do proměnných se dala použít i ve zbytku skriptu? (Např s využitím pole.)
Zjistil jsem, že se proměnné chovají jako lokální.
Př.:

grep -v "^#" /etc/fstab | while read disk bod zbytek
do echo -n . #mala uprava
done
echo "posledni: $disk na $bod"; #doplněno

vypíše jen ".....posledni: na " , protože proměnné $disk a $bod už jsou zapomenuty. Asi se externí příkazy jako třeba grep volají v samostatném bashi, který dostane jen hodnoty proměnných nastavených před jeho voláním, ale na původním místě proměnné nemění...

Takže jak to vyřešit, když chci data dál ve skriptu použít?

Pozn. funguje export do souboru (do echo "$disk na $bod" >> test.txt). Případně možná roura, ale obojí je asi dost nepraktické pro další použití ve skriptu. Zvlášt, když bych rovnou mohl použít pole.

Dík za odpovědi.
Martin Šín Re:Bash, 14. díl
Martin Šín 5. 06. 2010, 20:55:51
Odpovědět  Odkaz 
Byl to takový oříšek ;-), problém je, že se read ? pouští v jiném shellu než hlavní skript, a tak jediné co jsem vyspekuloval je toto:

grep -v "^#" /etc/fstab | {
while read disk bod zbytek
do
echo "$disk na $bod"
diskp=$disk
bodp=$bod
done
echo "posledni: $diskp na $bodp";
}
Milan Kozák Bash, 14. díl
Milan Kozák 6. 06. 2010, 13:15:18
Odpovědět  Odkaz 
Tohle již bylo nespočetněkrát řešeno. Např.:
http://www.abclinuxu.cz/poradna/linux/show/189942
Bash, 14. díl
bashovy zacatecnik 6. 06. 2010, 22:34:25
Odpovědět  Odkaz 
Díky oběma.
Odkaz http://www.abclinuxu.cz/poradna/linux/show/189942 dává úplné řešení,
ale úplně nejkomplexnější je tam odkazovaný http://mywiki.wooledge.org/BashFAQ/024.
Je tam i další zajímavá věc, kterou jsem hledal ( read -r a b c
Bash, 14. díl
bashovy zacatecnik 6. 06. 2010, 22:35:27
Odpovědět  Odkaz 
Je tam i další zajímavá věc, kterou jsem hledal ( read -r a b c *** "$foo" ... místo 3x* je 3x< (zde to asi server nebere))
Bash, 14. díl
F 1. 10. 2010, 12:29:55
Odpovědět  Odkaz 
a jak tohle resit pres ssh ?

bash -c "read -n 1 -t 10 ANS ; echo \$ANS;"
funguje dle ocekavani OK - vypise znak, ktery byl zmacknut.

ssh localhost bash -c "read -n 1 -t 10 ANS ; echo \$ANS;"
nefakci .. :(

Tam bude potreba nejake presmerovani stdin na ten z ssh, nebo tak neco ze ? Poradi nekdo ? Localhost pouzivam jen pro testovani, samozrejme na localhost se pripojovat pres ssh nema vyznam, misto localhost by byl nejaky vzdaleny server.
Re:Bash, 14. díl
F 1. 10. 2010, 13:26:52
Odpovědět  Odkaz 
aha :)
uz jsem na to prisel:

solution:
ssh -t localhost "bash -c \"read -n 1 -t 10 ANS ; echo \\\$ANS;\""

Odpovědět

Nejsou podporovány žádné značky, komentáře jsou jen čistě textové. Více o diskuzích a pravidlech najdete v nápovědě.
Diskuzi můžete sledovat pomocí RSS kanálu rss



 
 

Top články z OpenOffice.cz