# Úvod do UNIXu (SWI095x1h), 8. cvičení, 2005-04-03
# 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-08.reseni.txt,v 1.1 2005/04/13 16:28:50 jp Exp $
#

#---------------------------------------------------------------------
# signály, procesy
#---------------------------------------------------------------------

(sp1) dodatek k minulému cvičení, obsluha signálů v shellu, POSIX,
"-T" option (FreeBSD specific), ...

## při čekání na skončení potomka se signál se doručuje až po jeho
## skončení, viz POSIX (man sh)
##
## je rozdíl mezi posílání signálu z klávesnice vers. posílání
## pomocí kill

#---------------------------------------------------------------------
# proměnné, systémové proměnné
#---------------------------------------------------------------------

(v1) $$, $?, $!, $0, $#, $n, shift, ...

## použití shiftu např. pro posunutí na ,,začátek´´ ($1) po
## zpracování všech options

(v2) jednoduchý skript, který vypíše první tři parametry na
příkazové rádce. Test na to, jak se chová, zadají-li se parametry
jako:

1 2 3
"1" "2" "3"
"1" " " 2 3
"1 2" 3
1\ 2 " " 3
'1 2 3'
...atd.

(v3) lehký úvod do quotingu; dvojité uvozovky, jednoduché uvozovky,
backslash; backslah ve dvojitých uvozovkách, dvojité uvozovky v
jednoduchých, naopak, atd. atd. Jak vypsat doslova 12'4"$\89

## echo "'"; echo "\a"; echo "\""; echo "$TERM"; echo "\$TERM"
## echo "'"; echo "\a"; echo "\""; echo "$TERM"; echo "\$TERM"
##
## echo 12"'"4'"$\'89
## echo 12\'4\"\$\\89
## echo 12\'4'"$\'89
##
## Guide to Quoting:
## http://www.mpi-sb.mpg.de/~uwe/lehre/unixffb/quoting-guide.html#para:sh-input-interp


#---------------------------------------------------------------------
# kombinace příkazů
#---------------------------------------------------------------------

(kp1) pajpa, středník, &&, ||, { xxx; }, ( xxx ) a příklady na ně;
na příkladu vysvětlen rozdíl mezi "()" a "{}"

## echo 1; echo 2
## echo 1 && echo 2
## echo 1 || echo 2
## true && echo 2
## false || echo 2
## { echo 1; echo 2; } | wc -l
## { echo 1; echo 2; } > xxx
## ( echo 1; echo 2  ) > xxx
##
## Porovnejte:
## a=b; { echo $a; a=c; } > xxx; echo $a >> xxx
## a=b; ( echo $a; a=ci ) > xxx; echo $a >> xxx

(kp2) více informací o "||" a "&&", složitější kombinace, priorita
operátorů, ...

## false || echo 1 && echo 2
##
## echo test && echo ok || echo false
## echo test && false || echo false
##
## Velký rozdíl v těchto dvou příkazech:
##   false && false || echo false
##   false && { false || echo false; }
##

(kp3) napište příkaz, který vytvoří adresář "aaa" a pokud se to
podaří, vytvoří v něm prázdný soubor "bbb"; pokud se vytvoření
souboru "bbb" nepodaří, vypiš chybovou hlášku. Pokud se adresář
"aaa" nepodaří vytvořit, příkaz skončí (tj. i kdyby už adresář
existoval".

## toto je špatně, zkuste si to třeba v /root adresáři - zahlásí se
## ,,bbb´´ error, ale příkaz měl selhat už na nemožnosti vytvořit
## adresář "aaa":
##  mkdir aaa && touch aaa/bbb || echo "bbb error"
##
## toto je dobře:
##   mkdir aaa && { touch aaa/bbb || echo "bbb error"; }
##
## a tohle je nejlepší řešení:
##   mkdir aaa 2>/dev/null && { touch aaa/bbb || echo "bbb error"; } || echo "aaa error"
##

(kp4) napište příkaz, který pokud slovo v proměnné "word" je
obsaženo v souboru "/etc/passwd", vypíše "ok", jinak "false".

## word=pechanec
## grep $word /etc/passwd >/dev/null && echo ok || echo shit

#---------------------------------------------------------------------
# řídící struktury
#---------------------------------------------------------------------

(rs1) if-then-else-fi; while-do-done; case-esac; for-do-in-done;
různé formy zápisu (každé z rezervovaných slov na samostatné řádce,
celý zápis na jednu řádku); jejich návratová hodnota jako návratová
hodnota posledního příkazu; spojování těchto příkazů přes pajpu

## while true; echo -n '.'; sleep 1; done
##
## for i in 1 2 3; do echo $i; done
##
## for i in 1 2 3; do echo $i; done && echo ok
##
## if true; then true; else echo shit; fi && echo ok || echo shit
## if true; then false; else echo shit; fi && echo ok || echo shit
##
## for i in 1 2 3; do echo $i; done | grep -v 2

(rs2) napište příklad (kp4) pomocí konstrukce "if-then-else"

## if grep $word /etc/passwd >/dev/null; echo ok; else echo shit; fi

(rs3) read a while cyklus;
napište while cyklus, který projede všechny řádky /etc/passwd a
každou řádku pouze vypíše

## cat /etc/passwd | while read i; do echo $i; done

(rs4) break; continue a příklady na ně. Například vypisujte ve for
cyklu zadanou posloupnost čísel a pokud v daném čísle není dvojka,
vypište ho dvakrát. Pokud tam je, vypište dané číslo jen jednou.
Další příklad - modifikace předchozího - vypisujte zadaná čísla a
pokud narazíte na dvojku ve vstupu, ukončete cyklus.

## for i in 1 2 3; do echo $i; echo $i | grep 2 >/dev/null && continue; echo $i; done
## for i in 1 2 3; do echo $i; echo $i | grep 2 >/dev/null && break; done

(rs5) napište while cyklus, který projede všechny řádky z
/etc/passwd a pokud bude daný řádek obsahovat slovo z proměnné
"word", tak ukončete cyklus a vypište "ok". Nic jiného příkaz nesmí
vypsat.

## cat /etc/passwd | while read i; do echo $i | grep $word >/dev/null && break; done && echo ok
## cat /etc/passwd | while read i; do echo $i | grep $word >/dev/null && echo ok && break; done
##
## toto je špatně:
##   while read i < /etc/passwd; do ...
##
## protože příkaz while opakovaně spouští příkazy read, které vždy
## přečtou první řádku a tu uloží do proměnné. Pokud přesměrujete
## vstup do příkazu while, tak ten dává příkazu read vstup a tedy ho
## dává postupně, po řádcích.


(rs6) řídíci struktura "case"; ukázky jednoduchého použití

## a=a; case $a in a) echo aa;; b) echo bb;; esac

(rs6) case; ukázky složitějšího použití.

## a=a; case $a in *) echo aa;; b) echo bb;; esac
## a=a; case $a in ?) echo aa;; b) echo bb;; esac
## a=b; case $a in ?) echo aa;; b) echo bb;; esac
## a=aa; case $a in ?) echo aa;; b) echo bb;; esac
## a=bb; case $a in ?) echo aa;; bb) echo bb;; esac
## a=bb; case $a in aa|bb) echo aabb;; cc) echo cc;; esac
##
## pomocí "*" se implementuje ,,default´´ chování:
## case $a in
##    a) echo aa;;
##    b) echo bb;;
##    c) echo cc;;
##    *) echo "something else";;
## esac