Programování v shellu
Složené příkazy

Lukáš Bařinka

Náplň cvičení

Cílem cvičení jsou základní složené příkazy v shellu.

  • Podmínka
  • Cyklus
  • Příkaz test
  • Blok příkazů

Podmínka

  • Návratový kód ($?): 0 = úspěch, ostatní = neúspěch
  • příkaz && příkaz
  • příkaz || příkaz
  • if příkaz; then příkaz; else příkaz; fi
  • Návratový kód
    
    									~true; echo $?
    									~false; echo $?
    									~grep -m1 -q '^root:' /etc/passwd; echo $?
    									~grep -m1 -q '^rooot:' /etc/passwd; echo $?
    								
  • Podmíněné spuštění příkazu
    
    									~grep -m1 -q '^root:' /etc/passwd && echo "root nalezen"
    									~grep -m1 -q '^rooot:' /etc/passwd || echo "rooot nenalezen"
    								
  • Podmínka
    
    									~U=root
    									~getent passwd "$U" >/dev/null; echo $?
    
    									~if getent passwd "$U" >/dev/null; then
    									    echo "Uzivatel '$U' nalezen"
    									 else
    									    echo "Uzivatel '$U' nenalezen"
    									 fi
    								
  • Podmínka - negace
    
    									~if true; then
    									    :
    									 else
    									    echo false
    									 fi
    
    									~if ! true; then echo false; fi
    								
  • Větvení case (switch)
    
    									~case $( date +%H%M ) in
    									       0[0-6]??|07[0-2]?|19[3-5]?|2???) echo Není výuka;;
    									                         07[3-5]?|08??) echo 7:30 - 9:00;;
    									   091[5-9]|09[2-5]?|10[0-3]?|104[0-4]) echo 9:15 - 10:45;;
    									                         11??|12[0-2]?) echo 11:00 - 12:30;;
    									      124[5-9]|125?|13??|140?|141[0-4]) echo 12:45 - 14:15;;
    									                         14[3-5]?|15??) echo 14:30 - 16:00;;
    									   161[5-9]|16[2-5]?|17[0-3]?|174[0-4]) echo 16:15 - 17:45;;
    									                         18??|19[0-2]?) echo 18:00 - 19:30;;
    									                                     *) echo Přestávka;;
    									esac
    								

Cykly

  • while příkaz; do příkaz; done
  • for proměnná in seznam; do příkaz; done
  • for ((init;cond;iter)); do příkaz; done
  • while cyklus
    
    									~while sleep 5; do date; done
    									^C
    
    									~F=/abc/def/ghi/jkl/mno
    									~while (( ${#F} )); do
    									    printf '%s\n' "$F"
    									    F=$( sed 's,/[^/]*$,,' <<<"$F" )
    									 done
    									
    								
  • foreach cyklus - průchod seznamem prvků
    
    									~for i in *; do
    									    printf '%s : %d bytes\n' "$i" $( stat -c %s "$i" )
    									 done
    
    									~set -- {a..f}
    									~printf '%s\n' $# "$@"
    
    									~j=0
    									~for i; do
    									    printf '%d. arg. = %s\n' $(( ++j )) "$i"
    									 done
    								
  • for cyklus s aritmetickým výrazem
    
    									~for (( i=1; i<=100; i++ )); do
    									    printf '%s\n' $(( i*i ))
    									 done
    								

Test

  • Příkaz test, resp. příkaz [
    • test výraz
    • [ výraz ]
  • Aritmetické, řetězcové a souborové operátory
  • \( ... \), \!, -a / -o
  • Aritmetické operátory
    
    									~PS1='EXIT:$?\n'$PS1
    									~P=$( wc -l </etc/passwd )
    									~G=$( wc -l </etc/group )
    
    									~[ "$P" -lt "$G" ]
    									~[ "$P" -gt "$G" ]
    
    									~test "$P" -lt "$G"
    									~test "$P" -gt "$G"
    
    									~(( P < G ))
    									~(( P > G ))
    								

									-lt <
									-gt >
									-le-ge-eq =
									-ne !=
						
  • Řetězcové operátory
    
    									~[ "$PWD" = "$HOME" ]
    									~[ "$PWD" != "$HOME" ]
    									~[ "$USER" \< root ]
    									~[ "$USER" \> root ]
    
    									~[ -z "$FOO" ]
    									~[ -n "$FOO" ]
    								
  • Řetězcové Vs numerické operátory
    
    									~bond='  7' BOND='007'
    
    									~[ "$bond" = 7 ]
    									~[ "$BOND" = 7 ]
    									~[ "$bond" -eq 7 ]
    									~[ "$BOND" -eq 7 ]
    									~(( BOND == 7 ))
    
    									~BOND='008'; (( BOND == 8 ))
    									~BOND='010'; (( BOND == 8 ))
    								
  • Souborové operátory
    
    									~P=/etc/passwd
    									~[ -e "$P" ]     ~[ -r "$P" ]
    									~[ -f "$P" ]     ~[ -w "$P" ]
    									~[ -d "$P" ]     ~[ -x "$P" ]
    									~[ -L "$P" ]     ~[ -O "$P" ]
    									~[ -s "$P" ]
    
    									~[ "$HOME" -nt "$P" ]
    									~[ "$HOME" -ot "$P" ]
    									~[ "$HOME" -ef "$P" ]
    								
  • Logické operátory
    
    									~T=/tmp; ln -s "$T"
    
    									~[ -d ".$T" ]
    									~[ -L ".$T" ]
    									~[ -d ".$T" -a ! -L ".$T" ] && echo ".$T je adresar"
    									~[ -d "$T" -a ! -L "$T" ] && echo "$T je adresar"
    								
  • Test jako součást podmínky
    
    									~T=$( date +%H%M )
    
    									~if [ "$T" \< 0730 -o "$T" \> 1929 ]; then echo Není výuka
    									   elif [ "$T" \> 0729 -a "$T" \< 0900 ]; then echo 7:30 - 9:00
    									   elif [ "$T" \> 0914 -a "$T" \< 1045 ]; then echo 9:15 - 10:45
    									   elif [ "$T" \> 1059 -a "$T" \< 1230 ]; then echo 11:00 - 12:30
    									   elif [ "$T" \> 1244 -a "$T" \< 1415 ]; then echo 12:45 - 14:15
    									   elif [ "$T" \> 1429 -a "$T" \< 1600 ]; then echo 14:30 - 16:00
    									   elif [ "$T" \> 1614 -a "$T" \< 1745 ]; then echo 16:15 - 17:45
    									   elif [ "$T" \> 1759 -a "$T" \< 1930 ]; then echo 18:00 - 19:30
    									   else echo Přestávka
    									fi
    								

Bloky příkazů

  • { p1; p2; } - blok v aktuálním shellu
  • (p1; p2) - blok v subshellu
  • Blok v aktuálním shellu
    
    									~D=/tmp/foo
    									~cd "$D" || {
    									   mkdir "$D" && echo "Adresar '$D' vytvoren"
    									   cd "$D"
    									~} || echo "Nepovedlo se"
    								
  • Blok v subshellu
    
    									~D=$( date +%F-%T ) F=passwd
    									~(
    									   cd /etc
    									   L=$( wc -l < "$F" )
    									   printf '%s: %s [%d radku]:\n' "$F" "$D" "$L"
    									   cat "$F"
    									 ) > "$F.backup_$D"
    									~declare -p L
    									~less "$F.backup_$D"