2.11    Prostředí shellu

Př.
$ cat akt_baze1
:
# Aktualizace databáze baze1. Klíčový parametr jmeno
$EDITOR baze1
 echo "`date` $jmeno`" >> baze1
#
$ jmeno=KarelIV akt_baze1
<<vzad obsah vpřed>>

2.12    Shell jako programovací jazyk

Scénaře (skripty) jsou textové soubory, interpretované programem sh doporučuji studium příkazů, realizovaných jako scénáře (v adresářích /bin, /usr/bin a /etc a pod. )
<<vzad obsah vpřed>>

2.12.1    Příkaz eval - dynamické sestavení příkazové řádky

eval řetězcový_výraz

Př.

Scénář vypis vypíše stránkovaný obsah aktuálního adresáře v krátkém nebo dlouhém formátu.

$ cat vypis
:
# Použití: vypis typ
# typ=k krátký formát
# typ=d dlouhý formát
 typ_prikazu_k=ls
 typ_prikazu_d="ls -l"
 eval \$typ_prikazu_$1

<<vzad obsah vpřed>>

2.13    Řizení pořadí vykonávání příkazů

2.13.1    Seznam příkazů

Př.
 nohup cc *.c &
<<vzad obsah vpřed>>

2.13.2    Podmíněné zpracování příkazů

if příkaz1
then
 :
else
      příkaz2
fi


if příkaz1
then
	 příkaz2
fi

<<vzad obsah vpřed>>

2.13.3    Podmíněné příkazy

Příkaz if

if seznam_příkazů
then
      seznam_příkazů
fi

if seznam_příkazů
then
      seznam_příkazů
else
      seznam_příkazů
fi

if seznam_příkazů
then
      seznam_příkazů
elif seznam_příkazů
      seznam_příkazů
...
else
      seznam_příkazů
fi

Příkaz case

case řetězec in
      vzor) seznam_příkazů;;
           ...
      vzor) seznam_příkazů;;

esac

.

case $teplota in
 	vysoká | střední ) echo Zavři topení ;;
	velmi_vysoká) echo Zavři topení a otevři okno ;;
                   obrovská) echo Vyskoč z okna ;;
	nízká | velmi_nízká) echo Otevři topení ;;
 	*) echo Vše v pořádku
esac

<<vzad obsah vpřed>>

2.13.4    Příkaz test

-r soubor pravda, pokud soubor existuje a uživatel pro něj právo čtení
-w soubor pravda, pokud soubor existuje a uživatel pro něj právo zápisu
-w soubor pravda, pokud soubor existuje a uživatel pro něj právo spouštění
-f soubor pravda, pokud soubor existuje a je obyčejným souborem
-d soubor pravda, pokud soubor existuje a je adresářem
-c soubor pravda, pokud soubor existuje a je speciálním znakovým souborem
-b soubor pravda, pokud soubor existuje a je speciálním blokovým souborem
-p soubor pravda, pokud soubor existuje a je pojmenovanou rourou
-s soubor pravda, pokud soubor existuje a má nenulovou délku
-t [fd] pravda, je-li na daném terminálu otevřen soubor s popisovačem fd. Standardně fd=1.
-n s1 pravda, má-li řetězec s1 nenulovou délku
-z s1 pravda, má-li řetězec s1 nulovou délku
s1  = ;s1 pravda, jsou-li řetězce s1 a s2 totožné
s1 != s2 pravda, jsou-li řetězce s1 a s2 různé
s1 pravda, není-li s1 prázdný
n1 -gt n2 pravda, je-li celé číslo n1 větší než celé číslo n2
n1 -ge n2 pravda, je-li celé číslo n1 větší nebo rovno celému číslu n2
n1 -lt n2 pravda, je-li celé číslo n1 menší než celé číslo n2
n1 -le n2 pravda, je-li celé číslo n1 menší nebo rovno celému číslu n2

Operátory v pořadí klesající priority

!
negace
-a
konjunkce ( logické AND )
-o
disjunkce ( logické OR)
Př.

Scénář najdis má parametry počáteční adresář a jméno souboru. Najde všechny soubory se zadaným jménem v podstromu adresářů, od počátečního adresáře. Pro každý soubor vytiskne jeho úplnou cestu, přístupová práva pro aktuálního uživatele a typ souboru.

$ cat najdis 
#!/bin/sh 
if test $# != 2 
then  
        echo "Pouziti: $0 adresar prikaz" 1>&2 
        exit 1 
fi 
if [ ! -d $1  ] 
then 
        echo "$1 neni adresar"  1>&2
        exit 2 
fi 
cesta="" 
cesta=`find  $1 -name $2 -print 2>/dev/null` 
if [ -z "$cesta" ]  
then 
        echo "Soubor $2 nenalezen" 
        exit 3 
fi 
for  nalezena_cesta in $cesta 
do 
        clear 
        echo 
        echo "VYSLEDKY HLEDANI" 
        echo 
        echo "*****************************************************************" 
        echo  
        echo "Uplna cesta k souboru $2 je $nalezena_cesta" 
        [ -d $cesta ] && echo "soubor je adresar" 
        [ -r $cesta ] && echo "soubor je citelny pro uzivatele $LOGNAME" 
        [ -w $cesta ] && echo "uzivatel $LOGNAME muze do souboru psat" 
        [ -x $cesta ] && echo "uzivatel $LOGNAME muze soubor spoustet" 
        echo 
        echo "typ souboru  `file $nalezena_cesta`" 
        echo     
        echo "*****************************************************************" 
        echo  
        tput smso; echo "Enter  dalsi nalezeny soubor, k konec" 
        tput rmso; read  dalsi 
        if [ "$dalsi" = k ] -o [ "$dalsi" = K ] 
        then 
                exit 
        fi 
done 



Vyvolání pro všechny soubory .profile v adresáři /home

$ najdis /home .profile
<<vzad obsah vpřed>>

2.14    Cykly

2.14.1    Cyklus while

while seznam_příkazů do
      seznam_příkazů
done

2.14.2    Cyklus until

until seznam_příkazů
do
      seznam_příkazů
done

Cykly while a until mají testy na začátku

2.14.3    Cyklus for

for proměnná in seznam_slov
do
      seznam_příkazů
done

.

Postupné vyvolání manuálu pro Bourův shell, C-shell, a Kornův shell:

for druh_shellu in sh csh ksh
do
	 man $druh_shellu
done

.

Pro všechny soubory,jejichž jména jsou zadané jako argumenty scénáře přidáme na konec souboru celek:

for cast
do
	cat cast >> celek
done
<<vzad obsah vpřed>>

2.14.4    Předčasné opuštění a opakování cyklu

2.15    Návratový kód scénáře

<<vzad obsah vpřed>>

2.16    Provádění skupin příkazů v aktuálním a v podřízeném shellu

Př.

O souborech začínajících řetězcem ucet v aktuálním adresáři chceme zobrazit údaje z dlouhého formátu příkazu ls a - prvý a poslední řádek každého souboru po stránkách

 $ {ls -l ucet*; head -1 ucet*; tail +1 ucet*;} | more

Př.

Je třeba opravit a přeložit v adresáři $HOME/apl1/zdrojc programy v jazyce C tak, abychom po skončení této práce byli opět v původním adresáři:

 $ ( cd $HOME/apl1/zdrojc; vi *.c; cc *.c;)

To je evivalentní posloupnosti:

soucasny_adresar=`pwd`
cd $HOME/apl1/zdrojc
vi *.c
cc *.c

cd $soucasny_adresar
<<vzad obsah vpřed>>

2.17    Funkce v shellu

.

Skript kopie vytvoří záložní kopii souborů, jejichž jména se zadávají jako argumenty:

$ cat kopie 
#!/bin/sh 
#  
# Funkce pouziti vytiskne napovedu a nastavi kod navratu 1 
# 
pouziti() 
{ 

        echo "Pouziti: $0 soubor..." 1>&2 
        exit 1 
} 
# 
#Funkce zaloha zkopiruje soubor do soubor.bak 
zaloha() 
{ 
for soubor 
do 
        cp $soubor ${soubor}.bak 
done 
} 
#  
if [ $# -lt 1 ] 
then 
        pouziti 
        exit 1 
fi 
while [ $1 ] 
do 
        soubory="$soubory $1" 
        shift 
done 
zaloha  $soubory 

Vyvolání skriptu kopie pro zálohu všech dat v aktuálním adresář s trasováním:

$ sh - x kopie *
<<vzad obsah vpřed>>

2.18    Standardní vstup z textu scénáře

Př.

Scénář vpravo (vlevo) posune všechny řádky souboru zadaného jako argument o tabulátor vpravo (vlevo) a vypíše jej.

$ cat vpravo 
: 
if [ $# != 1 ] 
then  
        echo "Pouziti: $0 soubor" 1>&2 
        exit 1 
fi 
ex -s  $1 <<KONEC 
%>> 
x 
KONEC 
more $1  
$ cat vlevo 
:
if [ $# != 1 ] 
then 
        echo "Pouziti: $0 soubor" 
        exit 1 
fi 
ex -s $1 <<KONEC 
%<< 
x 
KONEC 
more $1  

Vyvolání scénářů

$vpravo pako
$vlevo pako


$ cat inputi 
#!/bin/sh 
# 
# Cteni celeho cisla  bez znamenka z klavesnice s kontrolou 
# 
while true 
do 
        echo -n  "Cislo= " > /dev/tty  
#        
#       Presmerovani na terminal pro pouziti ve tvaru  
#       promenna=`inputi` 
# 
#       Neni-li na systemu volba -n, pak zkus nasledujici 
# 
#       echo "Cislo= "\\c > /dev/tty 
# 
#       Pokud i toto nepracuje, napis napr. vlastni napr. 
# 
#       echon() 
#       { 
#               echo $1 | tr -d ' 
#' 
#       } 
# 
        read cislo 
        if expr "$cislo" : "[0-9 ]" > /dev/null 2>/dev/null 
        then 
                break 
        else 
                echo "Chybny znak v cisle" > /dev/tty 
        fi 
done 
echo $cislo 

<<vzad obsah vpřed>>

2.19    Obsluha přerušení v shellu

Procesu s číslem pid lze explicitně zaslat signál (přerušení) příkazem
kill [signál] pid;
některé signály se generují stiskem speciálních kláves. íScénář může odchytit signál ( přerušení) a zpracovat jej či potlačit příkazem trap:

trap příkazy signály.

Nejdůležitější čísla signálů:

0 ukončení shellu ( příkaz exit nebo při chybě shellu)
1 HANGUP (odpojení terminálu)
2 INTERRUPT (stisknutí klávesy )
3 QUIT (stisknutí kláves \)
9 KILL ( zrušení procesu)
11 chyba v adresování paměti (memory fault)
15 požadavek na terminál

Signály 9 a 11 nelze potlačit a není možné změnit standardní reakce příkazem trap.

Př..

Každý scénář, který zakládá dočasné soubory by měl jako elementární požadavek slušnosti je po sobě uklidit před normálním ukončením či při nuceném přerušení:

...
docasny_soubor=/tmp/pom_seznam$$
touch docasny_soubor
trap 'rm -f $docasny_soubor; exit' 0 1 2 3 15
 ...

Př..

Příklad složitějšího scénáře - manažer pro práci se soubory

Úkolem je napsat scénář msoub, který řeší tyto základní práce se soubory:

Manažer se vyvolá příkazem: msoub soubor...
$ cat msoub
#!/bin/sh
#
# Scénář msoub pro manipulaci se soubory
#
# Příkazy: oprava, prohlídka, tisk, vymazání se zadávají
# stisknutím počatečního písmena (nerozlišují se malá a # velká) a klávesy Enter
# Použití: msoub soubor...
#
# Funkce pouziti vytiskne nápovědu při nesprávném zadání
#
pouziti()
{
echo " Použití: $0 soubor..."
}
#
# Funkce navod vytiskne návod k ovládání menu
#
navod()
{
#
	 clear
	 tput cup 3 5; tput smso;
	 echo " M A N I P U L A C E S E S O U B O R Y"; tput rmso
	 tput cup 4 5
	 echo _________________________________________________
	 tput cup 5 25; tput smso;
	 echo -n "SOUBOR: "; tput rmso; echo $soubor
	 tput cup 7 5; tput smso
	 tput smso; echo -n O; tput rmso; echo -n "prava "
	 tput smso; echo -n P; tput rmso; echo -n "rohlídka "
	 tput smso; echo -n T; tput rmso; echo -n "isk "
	 tput smso; echo -n V; tput rmso; echo -n "ymazání "
	 tput smso; echo -n D; tput rmso; echo -n "alší "
	 tput smso; echo -n K; tput rmso; echo -n "onec "
	 tput cup 9 5
	 echo _________________________________________________
	 tput cup 11 5
	 echo -n "Vyber funkci prvním písmenem + Enter: "
 }
#
if [ $# -lt 1 ]
then
	 pouziti; exit 1
fi
for soubor in $*
do
 	if [ ! -f $soubor ]
 	then
 		echo "$soubor neexistuje"
 	fi
 	while true
	do
 		navod; tput smso
 		read odpoved dalsi; tput rmso
		 case $odpoved in
 			[Oo]) vi $soubor;;
			 [Pp]) vi -R $soubor;;
			 [Tt]) lp $soubor;;
			 [Vv]) rm -i $soubor;;
			 [Dd]) break;;
			 [Kk]) break 2;;
			 *) ;;
		 esac
 	done
done

Scénář má řadu nevýhod, dstranění jako cvičení - např.:

<<vzad obsah vpřed>>

2.20    Některé další vnitřní příkazy shellu

2.20.1    Prázdný příkaz

: (dvojtečka)

Na rozdíl od komentáře uvozeného # se komentář za : chápe jako argument a k zamezení případných náhrad bude někdy třeba text uzavřít do apostrofů či uvozovek.

2.20.2    Příkaz exec

exec [argument...]

Provede v aktuálním shellu příkazy zadané v argumentu.

2.20.3    Příkaz hash

hash [-r] [příkaz...]

2.20.4    Příkaz read

read [proměnná...]

2.20.5    Příkaz times

times

Vytiskne sumární uživatelské a systémové časy běžícího procesu.

2.20.6    Příkaz ulimit

ulimit [n]

2.20.7    Příkaz unset

unset [jméno...]

2.20.8    Příkaz wait

wait [n]

2.20.9    Příkaz expr

expr argumenty

Konstrukce výrazů

výraz \| výraz
vrací hodnotu prvého výrazu, jestliže ani jeden z obou není prázdný nebo nulový, jinak hodnotu druhého výrazu
výraz \& výraz
vrací hodnotu prvého výrazu, jestliže ani jeden z obou není prázdný nebo nulový, jinak hodnotu 0
výraz {=, \>, \>=, \<, \<=, != }výraz
jsou-li oba výrazy celočíselné, pak porovnává číselné hodnoty, jinak vrací řetězcové porovnání
výraz {+, -, \*, /, % }výraz
celočíselné sčítání, odečítání, násobení, dělení a zbytek po celočíselném dělení
výraz : výraz
porovnávání regulárních výrazů. Druhý argument je regulární výraz stejného typu jako např. u editoru ed. Operátor : vrací počet znaků, které v prvém výrazu vyhovují regulárnímu výrazu, zadaném v druhém výrazu nebo část prvého výrazu vyhovujícímu regulárního výrazu. V tomto případě je třeba uzavřít část regulárního výrazu uzavřít mezi \( a \).

Př.

 nazev_souboru='funkce.4GL'
 pocet_znaku=`expr "$nazev_souboru" : '.*\.\

<<vzad obsah vpřed>>

2.21    Podmíněné substituce v shellu

${proměnná:-řetězec}
${proměnná:=řetězec}
${proměnná:?}
${proměnná:?řetězec}
${proměnná:+řetězec}

Př.

echo ${datum:-`date`}
echo ${TERM:=vt102}
echo ${INFORMIXDIR:?"Proměnná nenastavena"}
echo ${INFORMIXDIR:?}
datum=`date`}
echo ${datum:+"Na svatýho Dyndy!}
<<vzad obsah