# Úvod do UNIXu (SWI095x1h), 10. cvičení, 2005-04-27
# SU1, Malá Strana, MFF UK
#
# Řešení jsou odladěná na FreeBSD 4.11-RELEASE, případné konkrétní
# situace se týkají stroje mail.kolej.
#
# $DevNullCZ: cviceni-10.reseni.txt,v 1.5 2005/04/27 16:23:04 jp Exp $
#

#---------------------------------------------------------------------
# příkaz test
#---------------------------------------------------------------------

(t1) použití, konvence '[', použití s operátory '&&' a '||', rozdíl
mezi '[ $a = b ]' a '[ "$a" = b ]', nutná mezera před ukončovací ']'

(t2) bez použití příkazu 'if' napište test, zda daný soubor existuje
a je to regulární soubor; pokud ano, vypište 'ok', pokud ne, vypište
'failed'


(t3) obdobně si zkuste otestovat, že zadaný řetězec je prázdný, že
je neprázdný, že zadané číslo je rovno 1 nebo 2 (použijte '-o' v
rámci příkazu test), že daný soubor existuje a není prázdný, ...


#---------------------------------------------------------------------
# zpracování řádky (input interpretation)
#---------------------------------------------------------------------

(ii1) základní kroky při zpracování příkazové řádky, rozdíl mezi sh
a bash, ...

# http://www.mpi-sb.mpg.de/~uwe/lehre/unixffb/quoting-guide.html

(ii2) konkrétní kroky při zpracování příkazové řádky:

# cd /etc; configs="*.conf"; ls $configs


(ii3) ,,blank interpretation''. Vysvětlení na konkrétních
příkladech:

# echo `ls`
# echo "`ls`"

odebrání koncových znaků nové řádky:

# echo `echo -e 'a\n\n\n\n'`
# echo "`echo -e 'a\n\n\n\n'`"
# echo "`echo -e 'a\n\n\n\nb'`"

(ii4) zpracování proměnných (není rekurzívní!!!) náhrada příkazů
pomocí ``, zpracování znaků v rámci ``

# rekurzitiva:          a='$b'; b=c; echo $a
# proměnné uvnitř ``:   a=1; echo `a=2; echo $a`

když chci v rámci `` vypsat řetězec "$a":

# note: uvnitř `` se dá použít zpětné lomítko pro escape znaků '$',
# '`' a '\'


# a=1; echo `a=2; echo \$a`
# a=1; echo `a=2; echo \\$a`

je tedy možné vnořovat znaky zpětných uvozovek:

# echo `echo \`echo x\``

(ii5) do proměnné x uložte obsah souboru, jehož jméno je obsaženo v
souboru y


(ii6) bez toho, aniž byste to zkusili, určete jaký výstup budou mít
následující příkazy:

# a=b; b=c; echo $$a
# a=b; b=c; echo \$$a
# a=b; b=c; echo \$\$a
# echo `echo \\\\`
# echo `echo \\\\$`


(ii7) rozdíl mezi těmito příkazy:

# for i in "`ls`"; do echo $i; done
# for i in "`ls`"; do echo "$i"; done


#---------------------------------------------------------------------
# eval
#---------------------------------------------------------------------
(e1) motivace, použití, ...

(e2) mějme definici dvou proměnných, a=b; b=c. Vypište obsah
proměnné 'b' pomocí 'eval' a proměnné 'a'.


(e3) konkrétní příklad použití eval z praxe. FreeBSD používá pro
definici statického routingu v /etc/rc.conf následující konstrukci,
kde proměnná 'static_routes' určuje existenci dalších proměnných:

# static_routes="vladislavka square cihelna osadni"
# route_vladislavka="82.119.254.128/28 -hopcount 1 82.119.254.2"
# route_square="82.119.254.144/29 -hopcount 1 82.119.254.18"
# route_cihelna="82.119.254.152/30 -hopcount 1 82.119.254.6"
# route_osadni="82.119.254.160/27 -hopcount 1 82.119.254.30"

a výstupem mají být tyto příkazy (stačí je vypsat tak, jak by byly
spuštěny):

route add 82.119.254.128/28 -hopcount 1 82.119.254.2
route add 82.119.254.144/29 -hopcount 1 82.119.254.18
...

Napište kód, který toto zajistí. Pro nastavení proměnných je buď
přímo vložte do svého skriptu, nebo lépe je uložte napr. do souboru
'rc.conf' a ve svém skriptu jej pak načtěte pomocí '. rc.conf'.


#---------------------------------------------------------------------
# ještě ke quotingu
#---------------------------------------------------------------------
(q1) pozor třeba i při použití SSH, například tyto dva příkazy jsou
velmi rozdílné, přestože se většinou zachovají stejně:

# ssh jp@xxx echo *.conf
# ssh jp@xxx echo \*.conf

#---------------------------------------------------------------------
# while a čtení z pajpy
#---------------------------------------------------------------------
(w1) shell pro každý příkaz v koloně vytváří vlastní subshell; pro
poslední příkaz to většinou platí také, někdy ne. Uživatel se s tím
setká typicky u přesměrování vstupu do složených příkazů:

# a=b; echo c | while read i; do a=$i; echo $a; done; echo $a
# c
# b

Tedy takto nelze obecně získat největší UID ze souboru /etc/passwd:

# max=0; grep -v ^# /etc/passwd | cut -f3 -d: | \
#  while read i; do [ "$i" -gt "$max" ] && max=$i; done; echo $max

Dá se to obejít malým trikem, který nechávám na prostudování doma
(viz 'man sh' a "UNIX FAQ's" part 3):

# max=0
# exec 0>&9
# exec </etc/passwd
#
# while read line; do 
#    expr "$line" : "^#" >/dev/null && continue
#    n=`echo $line | cut -f3 -d:`
#    [ "$n" -gt "$max" ] && max=$n
# done
# 
# echo $max
# exec 9>&0

#---------------------------------------------------------------------
# příklady
#---------------------------------------------------------------------
(a1) napište funkci, která pro zadaný parametr (číslo) určí, zda
běží nebo neběží proces s daným PID. Funkce vrací hodnotu podle
konvence shellu, tedy 0 pokud běží (true), 1 když ne (false).
Použití by pak mělo být možné například takto:

# is_pid_running 1111 && echo ok || echo shit