Felhasználói eszközök

Eszközök a webhelyen


oktatas:linux:shell_programozas

Ez a dokumentum egy előző változata!


< Linux

Shell programozás

  • Szerző: Sallai András
  • Copyright © Sallai András, 2011-2013, 2016-2020
  • Licenc: GNU Free Documentation License 1.3

Bevezetés

A shell programok végrehajtható parancsok gyűjteménye, vagyis egymás után írt parancsok listája egy állományban. Nevezhetjük egyszerűen shell scriptnek is.

A shell scripteknek nem kötelező kiterjesztést megadni. Ha mégis szeretnénk megadni akkor válasszuk az .sh kiterjesztést. A rendszer azonban nem a kiterjesztésből fogja eldönteni, hogy shell script vagy nem az.

Ha egy fájlba parancsokat írunk, azt shell scriptként futtatva a parancsok végrehajtódnak. A unixos rendszerekben a scripteket egy karakterpárral kezdjük:

#!

A rendszer ebből tudja, hogy valamilyen scriptről van szó. Ha egy hexa szerkesztővel nézzük:

hexedit scriptnev

Akkor azt mondhatjuk a következő kódú karakterrel kezdődik:

23 21

A unix alapú rendszerekben a futtatható fájloknak sincs kiterjesztése alapértelmezetten. A Linux például ELF binárisokat futtat. Egy ELF bináris fájl eleje mindig a következő byte sorozattal kezdődik:

7F 45 4C 46

Nézzük meg például az ls parancsunkat (Felhasználóként! Ne rendszergazdaként!).

hexedit /bin/ls

Kilépés Ctrl + C

Ha a hexedit nem lenne telepítve:

apt install hexedit

A scriptek, tehát #! kezdődnek, de honnan tudja a rendszer, hogy milyen scriptről van szó? A #! után adjuk meg az interpreter nevét és elérési útját. Perl script esetén például:

#!/usr/bin/perl

Bash shell script esetén, például:

#!/bin/bash

Python script esetén, például:

#!/usr/bin/python

Első lépések

  • Szükségünk van egy szövegszerkesztőre, amiben megírjuk a scriptet.
  • Futtathatóvá kell tennünk a scriptet.
    • Szintaktika:
      • chmod jogok script-neve
    • Példa:
      • chmod +x bar
      • chmod 755 bar
  • Futtatjuk a scriptet
    • Szintaktika:
      • bash script-neve
      • sh script-neve
      • ./script-neve
    • Példa:
      • $ bash bar
      • $ sh bar
      • $ ./bar

Megjegyzés

Az utolsó szintaktikában a ./ jelentése: az aktuális könyvtár, de csak ez.

A . (dot) karaktert használhatjuk önmagában is, ez induláskor nem hoz létre egy új shell másolatot.

Szintaktika:

. script-neve

Példa:

$ . foo

Ha egy olyan scriptet indítunk amelyik nem áll le azonnal (például vár adatbevitelre), akkor meggyőződhetünk a fentiekről ha futtatjuk a felhasználó nevén a pstree parancsot. Legyen a példa kedvéért egy joska nevű felhasználó aki a ker.sh nevű scriptet indítja. A scriptet ./ker.sh vagy . ker.sh formában indítja, ekkor lekérdezzük a folyamatfát:

pstree joska

A lehetséges kimenet ./ker.sh esetén:

bash───pstree

bash───ker.sh

A lehetséges kimenet . ker.sh esetén:

bash───pstree

bash

A különbséget a ps parancs is megmutatja:

ps u

Kapcsolónak csak a „u” kapcsolót kell megadni.

Azt már tudjuk, hogy egy shell sciptet mindig „#!” karakterekkel kezdjük és utána leírjuk az értelmező útvonalát. De hogyan deríthatő ki az értelmező útvonala? Mi most, Bash shell-t szeretnénk használni. A which parancs megmondja, hogy honnan fut egy parancs:

which bash

Megjegyzés

script.sh
#!/bin/bash
 
# egy soros megjegyzés
 
:'
Több
soros
megjegyzés
'

Kivitel

Hozzuk létre első „Helló Világ!” nevű shell scriptünket. készítsünk egy elso.sh nevű fájlt, melynek tartalma a következő:

elso.sh
#!/bin/bash
echo "Helló Világ!"

Adjunk rá futtatási jogot:

chmod +x elso.sh

Futtassuk:

./elso.sh

Ezek után minden további scriptünket így kell létrehoznunk.

Sorvége:

echo -n "Helló Világ!"

Utóbbi utasítás a -n hatására nem ír a sorvégére sortörést.

Az „Escape” karakterek engedélyezése:

echo -e "Helló Világ!"

A -e kapcsoló engedélyezi az escape karakterek értelmezését a karakterláncokban:

  • \a csengő
  • \b egy karakter törlése visszafelé
  • \c nem ír ki újsor karaktert
  • \f lapdobás
  • \n új sor
  • \r kocsi vissza
  • \t vízszintes tabulátor
  • \v függőleges tabulátor
  • \\ backslash
  • \nnn a karakter ASCII kódja nnn (oktálisan)

Az escape karakter a normál karakter egy speciális értelmezése. Az „a” például csengőhang, az „n” sortörés. Azt, hogy speciális escape értelmezés következik egy „\” visszaperjel karakterrel mondjuk meg. A következő parancs például a „Helló” és a „Világ!” szöveget külön sorba írja:

echo -e "Helló\nVilág!"

Formázott kimenet

A printf utasítással a kiírt változókat, értékeket több módon formázhatjuk. Elsőként lássunk egy szimpla változó kiíratást:

printf "%s\n" $HOME

A prrintf segítségével színezhetjük is a kimenetet:

printf "\033[0;32mszínes szöveg\n"
printf "\033[1;33mszínes szöveg\n"

Meg kell jegyezzem, az echo parancs a -e kapcsolóval értelmezi az escape szekvenciákat, és ugyanez a hatás elérhető:

echo -e "\033[1;33mszínes szöveg\n"

Unicode karakter kiíratása is lehetséges a \U escape szekvenciával. Lássuk az „üres” szót:

printf "%b" "Unicode Character (U+7a7a) \U7a7a \n"

A „U” nagy u helyett használhatunk „u” kis u-t is.

Véletlen generálás

Véletlen szám

Az alábbiakban többféle véletlen szám előállítási lehetőséget ismerhetünk meg.

echo $RANDOM
n=$RANDOM
echo $n

1 és 3 között egy szám:

 echo $(((RANDOM % 3)+1))

De lehet így is:

echo $((1 + RANDOM % 3))

0 és 4 közötti számot véletlenszerűen:

r=$RANDOM
R=$((r %= 5))
 
echo $R

0 és 4 közötti szám:

echo $(( $(od -An -N2 -i /dev/random) % 5))

Véletlenszám az od paranccsal:

od -A n -N 1 -t d < /dev/urandom

A -t d decimális formában kiírásról gondoskodik. A -N 1, egyetlen bájt vételét írja elő.

shuf -i 1-10 -n 1

Ha telepítve van a perl nyelv:

perl -e 'print int rand 10, "\n"; '

Véletlen bemenet

A shuf a bemenetére kapott sorokból véletlenszerűen választ, majd kiírja a kimenetre:

echo -e "1\n2\n3\n4\n5" | shuf -n 1

könyvtár tartalmából véletlenszerűen választás:

ls dir1 | shuf -n 1

Bevitel

Ebben a részben megnézzük, hogyan kérhetünk be a billentyűzetről értékeket.

echo -n "Szó: "
read SZOVEG

Egy szöveg bekérése a SZOVEG változóba. A bekérést a read utasítás végzi. Az előtte lévő echo utasítás jelzi a „Szó: ” képernyőre való írásával, hogy egy szó begépelését várjuk. Az echo -n kapcsolója a „Szó: ” szöveg után nem ír sortörést. Így a bekérés rögtön a kettőspont-szóköz után lehetséges.

Bekérés echo nélkül:

script.sh
#!/bin/bash
 
read -p "Felhasználónév: " USER
 
echo "A felhasználónév: "$USER

A bekérés szövegét echo nélkül is kitudjuk íratni a read -p kapcsolója segítségével.

Beolvasás tömbbe:

script.sh
#!/bin/bash
 
echo -n "Gyümülcsök: "
 
read -a GYUMOLCSOK
 
echo ${GYUMOLCSOK[0]}
echo ${GYUMOLCSOK[1]}

A read utasítás a -a kapcsoló hatására indexelt tömbváltozót hoz létre. Lásd „help read”.

A beolvasandó értékeket szóközzel tagolva adjuk meg. Például:

Gyümölcsök: körte alma barack szilva

Jelszó beolvasása:

script.sh
#!/bin/bash
 
echo -n "Jelszó: "
read -s JELSZO
 
echo
echo "A beírt jelszó: " $JELSZO
script.sh
#!/bin/bash
 
read -p "Jelszó: " -s JELSZO
 
echo
echo "A beírt jelszó: " $JELSZO

Alapértelmezett szöveg megadása:

script.sh
#!/bin/bash
 
read -e -i "joska" -p "Felhasználónév: " USER
 
echo "A beírt felhasználónév: "$USER

A „-e” kapcsoló is szükséges.

Változók és az értékadás

A változók kis és nagybetű érzékenyek. A SZAM és a szam változó két különböző változó. Az átláthatóság érdekében a változóneveket nagybetűvel szokás írni.

SZAM=3
SZOVEG="alma"
echo $SZAM
echo $SZOVEG

Az értékadó operátor előtt és után nem hagyhatunk whitespace karaktert, mert akkor a SZAM vagy SZOVEG változót egy parancsnak venné.

Kifejezés kiértékelése

expr 1 + 3

Az 1+3 összegét, azaz 4-et ad vissza

script.sh
#!/bin/bash
 
A=3
B=7
expr $A + $B
script.sh
#!/bin/bash
 
A=3
B=7
C=`expr $A + $B`
echo $C
script.sh
#!/bin/bash
 
A=3
B=7
C=`expr $A "*" $B`
echo $C
script.sh
#!/bin/bash
 
A=3
B=7
C=`expr \( $A "*" $B \) / 2 `
echo $C
script.sh
#!/bin/bash
 
A=3
B=7
C=`echo  \( $A "*" $B \) / 2 | bc`
echo $C

Gyökvonás:

script.sh
#!/bin/bash
 
echo sqrt\(9\) | bc

Hatványozás:

script.sh
#!/bin/bash
 
echo 2 ^ 8 | bc

Szelekció

if

#!/bin/bash
SZAM=2
if [ $SZAM -eq 2 ]
then
    echo "Egyenlo"
else
    echo "Negy egyenlo"
fi

Az -eq egyenlőséget vizsgál. Használható még a „=” vagy a „==” karakterek is, viszont ezen operátorok előtt és után kötelező egy vagy több whitespace karakter.

#!/bin/bash
SZAM=2
if [ $SZAM -ne 2 ]
then
    echo "Nem egyenlő kettővel"
else
    echo "Egyenlő kettővel"
fi

A -ne azt jelenti nem egyenlő. Használható helyette a != alak is.

#!/bin/bash
SZAM=2
if [ $SZAM -gt 2 ]
then
    echo "Nagyobb"
else
    echo "Kisebb vagy egyenlő mint kettő"
fi
#!/bin/bash
SZAM=2
if [ $SZAM -lt 2 ]
then
    echo "Kisebb mint kettő"
else
    echo "Nagyobb vagy egyenlő mint kettő"
fi
#!/bin/bash
SZAM=2
if [ $SZAM -le 2 ]
then
    echo "Kisebb vagy egyenlő mint kettő"
else
    echo "Nagyobb mint kettő"
fi
#!/bin/bash
SZAM=2
if [ $SZAM -ge 2 ]
then
    echo "Nagyobb vagy egyenlő"
else
    echo "Kisebb"
fi

And operátor

Egyszerre nem csak egy, hanem több feltételt is meg szeretnénk vizsgálni.

if [[ $num -eq 3 && "$str" == foo ]]
then
 
  # Utasítások
fi

elif

#!/bin/bash
 
read -p "Gyümölcs: " fruit
 
if [ "$fruit" = "alma" ]; then
	echo "Ez alma"	
elif [ "$fruit" = "körte" ]; then
    echo "Ez körte"
else
	echo "Nem alma és nem körte"	
fi

select

valaszt.sh
#!/bin/bash
 
select i in "egy" "kettő" "három"
do
    echo Ezt választottad:
    echo $i
done

Kiírja az „egy”, „kettő”, „három” szavakat sorszámokkal bevezetve. Valójában egy ciklus is elindul. Mindig várja, hogy válasszunk egyet. A ciklus a Ctrl + C billentyűkombinációval is.

A ciklus persze megszakítható a break utasítással a cikluson belülről is.

valaszt.sh
#!/bin/bash
 
select i in "egy" "kettő" "három" "kilépés"
do
    echo Ezt választottad:
    echo $i
    if [[ "$i" = "kilépés" ]] ; then
	break
    fi
done

És, vagy logikai operátorok

Vagy:

script.sh
#!/bin/bash
 
A=0
B=1
 
if [[ $A -eq 1 || $B -eq 1 ]]
then
    echo "Ok"
else
    echo "Nem ok"
fi

És:

script.sh
#!/bin/bash
 
A=0
B=1
 
if [[ $A -eq 1 && $B -eq 1 ]]
then
    echo "Ok"
else
    echo "Nem ok"
fi

Kevert:

script.sh
#!/bin/bash
 
A=1
B=0
C=1
 
if [[ ($A -eq 1 || $B -eq 1) && $C -eq 1 ]]
then
    echo "Ok"
else
    echo "Nem ok"
fi

Szelekció másként

Szimpla szelekció

#!/bin/bash
 
A=1
 
[ $A -eq 1 ] && echo "Ok" || echo "Nem ok"

Vagy logikai operátor

#!/bin/bash
 
A=1
B=1
 
[ $A -eq 1 ] && [ $B -eq 1 ] && echo "Ok" || echo "Nem ok"

És logikai operátor

#!/bin/bash
 
A=1
B=1
 
[ $A -eq 1 ] && [ $B -eq 1 ] && echo "Ok" || echo "Nem ok"

Vegyes logikai operátorok

#!/bin/bash
 
A=1
B=1
C=0
 
([ $A -eq 1 ] || [ $B -eq 1 ]) && [ $C -eq 1 ] && echo "Ok" || echo "Nem ok"

Több ágú elágazás

echo "[O]lvas"
echo "[H]ozzáfűz"
echo "[S]zerkeszt"
 
read menupont
 
case "$menupont" in
  "O" | "o" )
      echo "Olvasási műveletek"
      ;;
  "H" | "h" )
      echo "Hozzáfűzési műveletek"
      ;;
  "S" | "s" )
      echo "Szerkesztési műveletek"
      ;;
esac

Iteráció

for

Számok 1-től - 10-ig, variációk:

for i in `seq 1 10`
do
    echo $i
done
for i in `seq 1 10`; do  echo $i ; done
for i in 1 2 3 4 5 6 7 8 9 10
do
    echo $i
done

Egy könyvtár tartalmát végig vesszük:

for i in `ls /etc`
do
    echo $i
done

A példában listázzuk az /etc könyvtár tartalmát.

Zip fájlok feldolgozása:

#!/bin/bash
 
for file in *
do
    if [[ "$file" = *.zip* ]]
    then
	echo "$file"
    fi
done
#!/bin/bash
 
for (( n=0; n<10; n++ ))
do
	echo "Helló"
done
#!/bin/bash
 
for (( n=0; n<10; n++ ))
do
	echo $n
done

while

Amíg típusú ciklus (while)

#!/bin/bash
 
SZAMLALO=1
 
while [ $SZAMLALO -lt 11 ]
do
        echo $SZAMLALO
        let SZAMLALO=SZAMLALO+1
done

Számok bekérése nulla végjelig:

#!/bin/bash
 
SZAM=1
 
while [ $SZAM -ne 0 ]
do
	echo -n "Szám: "
	read SZAM
done

Számok bekérése nulla végjelig, közben összegzés.

#!/bin/bash
 
SZAM=1
SZUM=0
 
while [ $SZAM -ne 0 ]
do
	echo -n "Szám: "
	read SZAM
	let SZUM=$SZUM+$SZAM
done
 
echo "Összeg: " $SZUM

A let nélkül sztringkét adja össze.

Végtelen ciklus létrehozása:

while true
do
   #amit csinálunk a végtelen ciklusban
done

Másik módszer a végtelen ciklusra:

while :
do
   #amit csinálunk a végtelen ciklusban
done
while :
do
   echo -n "Számot: "
   read SZAM
   if [ $SZAM -lt 1 ]
   then
      exit 0
   fi
done

Fájl olvasása

script.sh
#!/bin/bash
 
while read sor
do
    echo $sor
done < gy.txt
script.sh
#!/bin/bash
 
cat gy.txt | while read sor
do
    echo $sor
done

Könyvtár tartalmának olvasása

A .txt kiterjesztésű fájlok olvasása:

script.sh
#!/bin/bash
 
DIR=konyvtar/alkonyvtar
 
cd $DIR
 
find $DIR -name '*.txt' | while read sor
do
    echo $sor
done

until

#!/bin/bash
 
SZAMLALO=1
 
until [ $SZAMLALO -gt 10 ]
do
        echo $SZAMLALO
        let SZAMLALO=SZAMLALO+1
done

Tömbök

tomb=( "egy" "kettő" "három")

Hivatkozás egy tömbelemre:

echo ${tomb[1]}

Ez a második elemet adja vissza, vagyis az indexelés 0-val kezdődik.

A tömb elemei így is felvehetők:

tomb[0]=egy
tomb[1]=kettő
tomb[2]=három
 
echo ${tomb[1]}

A tömb tulajdonságai

#!/bin/bash
 
${tomb[*]}    # a tömb összes eleme
 
${!tomb[*]}   # a tömb összes indexe
 
${#tomb[*]}   # a tömb elemeinek száma
 
${#tomb[0]}   # a 0-dik elem hossza

A tömb bejárása

#!/bin/bash
 
etelek=(
        "Halsaláta"
        "Zöldségkör"
        "Húsleves"
        "Narancs-joghurt"
)
 
count=${#etelek[@]}
 
for item in ${ketogenEtelek[*]}
do
   echo $item
done

A tömb bejárása a for in szerkezettel, csak akkor működik, ha nincs szóköz a tömb elemeiben. Ha a tömb elemei szóközöket is tartalmaznak, akkor a következő ciklus alkalmas bejárásra:

#!/bin/bash
 
etelek=(
        "Halsaláta (uborka, tonhal, tejföl)"
        "Zöldségkör (tejföl, túró, zöldségek)"
        "Húsleves"
        "Narancs joghurt"
)
 
count=${#etelek[@]}
 
for (( i=0; i<${count}; i++))
do
    echo ${ketogenEtelek[$i]}
done
bejar.sh
#!/bin/bash
 
tomb=(
	"alma"
	"körte"
	"barack"
	"szilva"
	)
 
for i in "${tomb[@]}"
do
	echo $i
done

String

Hossz

SZOVEG="Nagy János"
meret=${#SZOVEG}
echo $meret
SZOVEG="abc123"
HOSSZ=$(printf "%s" "$SZOVEG" | wc -c)
echo ${#SZOVEG}
echo -n $SZOVEG | wc -m
echo -n $SZOVEG | wc -c
printf $SZOVEG | wc -m
expr length $SZOVEG
expr $SZOVEG : '.*'

Kisbetű, nagybetű

STR="Alma"

echo $STR  # alma

echo ${STR,,}  # alma


echo ${STR^^}  # ALMA

A fenti megoldás, csak a 4.x Bash verziótól működik.

Használhatjuk a tr parancsot, ami viszont nem viszi a magyar ékezetes karaktereket.

STR="Alma"
echo "$STR" | tr '[:upper:]' '[:lower:]'

Megoldás lehet még az awk használata:

echo "ÁRVÍZTŰRŐ" | awk '{print tolower($0)}'

A Bash megoldás esetén használhatunk egyetlen ^ vagy , karaktert. Ekkor csak az első karakterre vonatkozik a beállítás.

STR=árvíztűrő; echo ${STR^}
Árvíztűrő

Milyen betűk legyenek nagybetűk:

STR=árvíztűrő; echo ${STR^^[v,z]}
árVíZtűrő

Ékezetlenítés

Repülő ékezetek, normál ékezet helyett:

echo árvíztűrő | iconv -f UTF-8 -t ASCII//TRANSLIT
# apt install unaccent
$ echo árvíztűrő | unaccent utf-8
arvizturo
$ echo árvíztűrő | sed 'y/áíéóöőúüű/aieooouuu/'

Tartalmaz-e?

#!/bin/bash
 
if [[ $a == *"é"* ]]
then
	echo "Van benne é betű"
else
	echo "Nincs benne é betű"
fi

String bejárása karakterenként

#!/bin/bash
 
a=béla
for (( i=0; i<${#a}; i++ ))
do
	echo "${a:$i:1}"
done

Regex

Az [a-z] mint megfelel az angol ábécé betűinek plusz áíóöúü betűknek, de nem felel meg a ő és ű betűknek.

#!/bin/bash
 
a=belí
 
if [[ $a =~ ^[a-z]+$ ]]
then
	echo "Megfelel"
else
	echo "Nem felel meg"
fi

String darabolása

darabol.sh
#!/bin/bash
 
str="alma:körte:barack:szilva"
 
IFS=':' read -ra tomb <<< "$str"
 
echo ${tomb[0]}

Heredoc szintaxis

naplo.sh
#!/bin/bash
 
date=$(date "+%Y-%m-%d")
 
cat << EOT
 
==========
 
$date
 
Óra:
Téma:
Hiányzók:
	1 óra:
	2 óra:
	3 óra:
Dolgozat:
Hetes:
 
EOT

Visszatérési érték

Vizsgáljunk meg egy program végrehajtásának sikerességét. A példában az smbmount parancsot vizsgáljuk a végrehajtás sikerességéről.

#!/bin/bash
 
smbmount //server/megosztasnev -o username=joe,password=titok,uid=joe,gid=csoport
 
if [ $? == 0 ]
then
    echo
    echo "A végrehajtás sikeres"
    echo
else
    echo
    echo "Hiba a végrehajtás során"
    echo
fi

Karaktersorozat vizsgálatok

Operátorok:

= egyenlő
!= nem egyenlő
< rövidebb
> hosszabb
-z $NEV a NEV üres
#!/bin/bash
 
ELSO="Kati"
MASODIK="Kati"
 
if [ $ELSO = $MASODIK ]
then
    echo Egyezik
else
    echo Nem egyezik
fi

Üres vagy nem üres a string:

#!/bin/bash
 
ELSO=""
 
if [ -z $ELSO ]
then
    echo Üres
else
    echo Nem üres
fi

Az ASCII táblában előrébb vagy hátrább van-e:

#!/bin/bash
 
ELSO="szilva"
MASODIK="zalma"
 
if [ $ELSO \> $MASODIK ]
then
    echo "Hátrébb van"
else
    echo "Előrébb van"
fi

vagy így:

#!/bin/bash
 
ELSO="szilva"
MASODIK="zalma"
 
if [[ $ELSO > $MASODIK ]]
then
    echo "Hátrébb van"
else
    echo "Előrébb van"
fi
#!/bin/bash
 
ELSO="s*"
 
# minta egyezés
if [[ $ELSO == s* ]]
then
    echo "s-el kezdődik"
else
    echo "Nem s-el kezdődik"
fi
#!/bin/bash
 
ELSO="s*"
 
# literális egyezés
if [[ $ELSO == "s*" ]]
then
    echo "s* van benne"
else
    echo "Nem s* van benne"
fi
#!/bin/bash
 
ELSO="s*"
 
# literális egyezés
if [ "$ELSO" == "s*" ]
then
    echo "s* van benne"
else
    echo "Nem s* van benne"
fi

Függvények, eljárás használata

Függvény:

minta.sh
function kiir() {
    echo "Helló Világ"
}
 
kiir

Függvény paraméterrel:

minta.sh
function kiir() {
    echo $1
}
 
kiir "Ezt írd ki"

Bemenő paraméter és visszatérési érték:

fg.sh
#! /bin/bash
 
function dupla() {
		local res=$(echo "$1 * 2" | bc)
		echo "$res"	
}
 
result=$(dupla 3)
echo $result

Ez a megoldás is működik, de az előbbi korrektebb:

vissza.sh
#! /bin/bash
 
function dupla() {
		res=$(echo "$1 * 2" | bc)	
}
 
dupla 3
echo $res

Példa:

#!/bin/bash
 
# Rekurzívan az alkönyvtárakban is átnevez minden fájlt kisbetűsre
# Jelenleg csak fájlokra működik, könyvtárakra nem.
# Latin2-es környezetben működik (1 karakter == 1 byte), UTF-8-ban nem.
# UTF-8-as környezetben a tr helyett a sed parancsot használjuk!
 
function files()
{
    for i in * ; do
      if [ -f "$i" ]; then
        j=`echo "$i" | tr '[:upper:]' '[:lower:]'`
        if [ "$i" != "$j" ]; then
          mv -i "$i" "$j"
        fi
      fi
    done
}
 
 
function dirs()
{
    for i in *; do
	    if [ -d "$i" ]; then
	      cd "$i"
	      dirs
	      files
	      cd ..
	    fi
    done
}
 
dirs
files

Változók hatásköre

A következő script szemlélteti a változók hatáskörét. A local kulcsóval létrehozott függvényen belüli változó nem látszik csak a függvényben. Az $ERO nevű változó viszont globális, mindenhol látszik.

#!/bin/bash
 
ERO="85"
function csokkent {
    local MERTEK=5
    echo "Erő csökkentése..."
    ERO=`expr $ERO - $MERTEK`
}
echo "Erő: $ERO"
csokkent
echo "Erő csökkentés után: $ERO"
echo "Csökkentés mértéke: $MERTEK"

Külső változó felhasználása:

#!/bin/bash
 
szam=45
 
function csinal() {
  szam=100
  echo "Működik"
}
 
csinal
echo "$e"

Fájl és könyvtár tesztek

Használható kapcsolók listája

  • -b filename A fájl speciális blokk?
  • -c filename A fájl speciális karakterfájl?
  • -d directoryname A könyvtár létezik?
  • -e filename A fájl létezik?
  • -f filename A fájl általános fájl, nem egy könyvtár?
  • -G filename Ha a fájl létezik, érvényes tulajdonos érvényes csoportazonosító?
  • -g filename true ha fájl létezik és van set-group-id
  • -k filename Sticky bit
  • -L filename Szimbolikus link
  • -O filename True ha fájl létezik és az felhasználó érvényes azonosító.
  • -r filename Ellenőrzés, ha a fájl olvasható.
  • -S filename Ellenőrzés, ha a fájl socket
  • -s filename Ellenőrzés, ha a fájl nem nonzero méretű
  • -u filename Ellenőrzés, ha set-ser-id bit be van állítva
  • -w filename A fájl írhatóságának ellenőrzés
  • -x filename A fájl futtathatóságának olvasása

A fájl létezésének ellenőrzése

#!/bin/bash
file="adat.txt"
if [ -e $file ]; then
	echo "A fájl létezik"
else 
	echo "A fájl nem létezik"
fi 

Első paraméter létezésének vizsgálata

#!/bin/bash        
if [ -z "$1" ]; then 
    echo usage: $0 directory
    exit
fi

Könyvtár vizsgálat

Példa a könyvtárvizsgálatra:

if [ -d "$DIRECTORY" ]; then
    # Mit tegyünk, ha a $DIRECTORY könyvtár létezik
fi

A könyvtár neve (esetleg útvonala) a $DIRECTORY változóban találjuk.

Ha a könyvtár nem létezik:

if [ ! -d "$DIRECTORY" ]; then
    # Mit tegyünk, ha a $DIRECTORY nem létezik
fi

Parancs kimenete

[ -z "`ls`" ] && echo "Nincs fájl"

A [ -z az ls által visszaadott sztring hosszát vizsgálja, hogy az 0 értékű-e.

[ -n "`ls`" ] && echo "Van valamilyen fájl"

A [ -n az ls által visszaadott sztring hosszát vizsgálja, hogy az nagyobb-e mint 0.

Tesztek a test paranccsal

Az if utasítást után a test parancs is használható feltételek meghatározására. A következőkben erre látunk példát.

test <KIFEJEZÉS>
[ <KIFEJEZÉS> ]

A két utasítás visszatérhet 0-val (TRUE) vagy 1 (FALSE) értékekkel.

#!/bin/bash
 
if test -e /etc/group
then
  echo "A csoportfájl létezik..." >&2
else
  echo "Valami nem kerek!" >&2
  exit 1
fi

A test utasítás után a kifejezés egy -e kapcsolóval kezdődik. Azt mondja egy fájl létezését akarjuk tesztelni. Ez után következik, hogy melyik fájlt szeretnénk tesztelni.

A fenti utasításnak teljesen megfelel a „[” karakter. Ha megnézzük az /usr/bin könyvtárat, akkor találni fogunk ott egy ilyen futtatható programot.

#!/bin/bash
 
if [ -e /etc/group ]
then
  echo "A csoportfájl létezik..." >&2
else
  echo "Valami nem kerek!" >&2
  exit 1
fi

Beépített változók

$0 A script neve
$1 paramét1
$2 paramét2
$3 paramét3
$4 paramét4
$5 paramét5
$6 paramét6
$7 paramét7
$8 paramét8
$9 paramét9
$# argumentumok száma
$@ az összes argumentum
$? az utolsó folyamat kilépési kódja
$LINENO a script aktuális sora
$HOSTNAME hol fut a script
$USER a scriptet futtató felhasználó
$SECONDS a futtatás kezdete óta eltelt idő
$RANDOM minden hivatkozáskor más véletlen számot ad

Fájlok, könyvtárak neveinek kezelése

A következő példákban egy könyvtárban található fájlok vagy alkönyvtárak tartalma helyett, azok nevein hajtunk végre valamit. Jelenleg csak kiíratjuk a nevüket.

olvas.sh
#!/bin/bash
 
FAJLOK='*.txt'
ls $FAJLOK | while read next_file
do
	echo $next_file
done
olvas.sh
#!/bin/bash
 
DIR=/home/utvonal
 
cd $DIR
 
for FILE in *
do
    echo Könyvtárnevek: $FILE
done
olvas.sh
#!/bin/bash
 
DIR=/home/utvonal
 
cd $DIR
 
find $DIR -name '*.txt' | while read filename
do
    echo $filename
done

Fájlok tartalmának kezelése

A következő példa bemutatja hogyan tudjuk olvasni egy fájl tartalmát.

while read sor
do
    echo $sor
done < gy.txt

Ebben a példában is egy fájl tartalmát olvassuk, kicsit másként.

cat gy.txt | while read sor
do
    echo $sor
done

Backup

Egyszerű archiválás:

#!/bin/bash
tar -czf joskadokuarchiv.tar.gz /home/joska/doku

Egy összetettebb archiváló:

#!/bin/bash
 
DATUM=$(date +%Y%m%d)
MENTENDO=/home/andras/bin
KIMENET=mentes-joskahome_$DATUM.tar.gz
 
tar -czf $KIMENET $MENTENDO

Paraméterek használata

#!/bin/bash
 
if [ "$#" == "0" ] 
then
    echo "Használat: ./parosit.sh Név1 Név2"
    exit
fi
 
echo "Ennyi nevet írtál: $#"
 
echo $1 és $2 jó választás együtt
 
echo "A paramétereid: $@"

Szignálok elkapása (trap)

A trap paranccsal szignálokat kaphatunk el. Ha valaki megnyomja például a Ctrl + C, akkor a script befejezése előtt még tehetek valami a „csinald” nevű függvényben. Persze tetszőleges függvény írható a helyére.

#!/bin/bash
 
trap csinald INT
 
csinald()
{
    echo Valaki megnyomta a Ctrl + C! Nem kéne
}
 
sleep 5

Temp fájlok

$ mktemp vmi.XXX
 vmi.YzM

A program kiírja milyen fájlt hoz létre. Az X-ek heléyre véletlen karaktereket helyettesít a program.

Lehet hosszabb is:

mktemp vmi.XXXXXXXX

A következő módon kinyerhető a fájl neve:

TEMP=$(mktemp vmi.XXX)

Ezek után így használjuk:

TEMP=$(mktemp /tmp/temporary-file.XXXXXXXX)
echo valami > ${TEMP}

Naplózás

Ha szeretnénk, hogy a script a /var/log könyvtárba nalózzon, akkor hozzunk ott létre a script számára egy könyvtárat:

# mkdir /var/log/sajatScriptNev

Naplózás a /var/log/syslog fájlba is történhet a logger nevű parancs segítségével:

logger uzenet

Megadható a script neve is:

logger –t ScriptNev “Helló Világ”

Függelék

Futtatható fájlok

A futtatható fájlok miről ismerjük fel, itt vannak megadva:

/proc/sys/fs/binfmt_misc

Telepítés

apt-get -y install mc >/dev/null 2>&1
aptitude -y install mc >/dev/null 2>&1

Aktuális könyvtár

Parancssorból az aktuális könyvtárnév, útvonal nélkül:

basename $PWD

Másik lehetőség:

echo ${PWD##*/}

Esetleg így:

ACTDIR=$(basname $(pwd))
echo $ACTDIR

Példák

Másolás időbélyeg alapján

Legrégebbi fájl másolása:

script.sh
#!/bin/bash
 
cd /útvonal/könyvtár
cp `ls -t1 *.txt | tail -1` /másik/útvonal/könyvtár/

Legújabb fájl mozgatása:

script.sh
#!/bin/bash
 
cd /útvonal/könyvtár
cp `ls -t1 *.txt | head -1` /másik/útvonal/könyvtár/

Feltöltés FTP-re

fel.sh
cd /útvonal/könyvtár
wput ./ ftp://felhasználónév:jelszó@url/könyvtár/
fel2.sh
#!/bin/sh
 
USERNAME=jozsi
PASSWORD=titok
HOST_NAME=localhost
LOG=naplo.txt
BATCH=id_batchfile
 
echo "user $USERNAME $PASSWORD" > $BATCH
echo "bin" >> $BATCH
echo "send egy.txt" >> $BATCH
echo "send ketto.txt" >> $BATCH
echo "exit" >> $BATCH
 
ftp -n -v $HOST_NAME < $BATCH > $LOG
 
rm $BATCH
fel3.sh
#!/bin/sh
 
USERNAME=jozsi
PASSWORD=titok
HOST_NAME=localhost
LOG=naplo.txt
 
ftp -n -v $HOST_NAME > $LOG <<EOF
 
quote user $USERNAME
quote pass $PASSWORD
bin
send egy.txt
send ketto.txt
exit
 
EOF
fel4.sh
#!/bin/sh
 
USERNAME=jozsi
PASSWORD=titok
HOST_NAME=localhost
LOG=naplo.txt
 
ftp -n -i -v $HOST_NAME > $LOG <<EOF
 
user $USERNAME $PASSWORD
bin
send egy.txt
send ketto.txt
exit
 
EOF

Így bekéri a jelszót

fel5.sh
#!/bin/sh
 
USERNAME=jozsi
HOST_NAME=localhost
LOG=naplo.txt
 
ftp -n -i -v $HOST_NAME > $LOG <<EOF
 
user $USERNAME 
password
bin
send egy.txt
send ketto.txt
exit
 
EOF
fel6.sh
#!/bin/sh
 
USERNAME=jozsi
PASSWORD=titok
HOST_NAME=localhost
LOG=naplo.txt
 
ftp -n -i -v  > $LOG <<EOF
open $HOST_NAME
user $USERNAME $PASSWORD
bin
send egy.txt
send ketto.txt
exit
 
EOF

Kicsit más:

fel7.sh
#!/bin/sh
 
USERNAME=jozsi
PASSWORD=titok
HOST_NAME=localhost
LOG=naplo.txt
 
ftp -n -v $HOST_NAME  <<EOF >> $LOG 2>&1
quote user $USERNAME
quote pass $PASSWORD
bin
prompt off
mput *.txt
exit
EOF

Dátum

Dátum darabolása

datum.sh
#!/bin/bash
 
read Y m d H M <<<$(date "+%Y %m %d %H %M")
 
echo Az év: $Y
echo A hónap: $m
echo A nap: $d
echo Az óra: $H
echo A perc: $M

Naplófájl figyelése

figyel.sh
STR=elnok
tail -f /var/log/syslog |
while read -r sor
do
    [[ "$sor" != *$STR* ]] && continue
	echo "Volt bejegyzés"
done
exit

Visszaszámlálás

A script használja az espeak programot. Ha nincs telepítve:

apt-get install espeak

Kimondva:

visszaSzamolKimondva.sh
for i in {"öt", "négy", "három", "kettő", "egy", "zéró"};do espeak -vhu "$i" && sleep 0.5; done

Ugyanaz kiírva:

visszaSzamolKiirva.sh
for i in {5..1};do echo -n "$i. " && sleep 1; done

Lejárt műszakik figyelése

Egy fájlban tároljuk melyik járműnek mikor jár le a műszakija. Egy scripttel pedig időnként, például időzítve ellenőrizzük, és hangosan kimondatjuk, ha körülbelül 2 hónap van a műszaki lejártáig.

vehicles.txt
Rendszám:Műszaki lejár:Szükséges figyelmeztetés:Gyártmány:Egyéb
ABC-123:2018-08-22:igen:Lada:Nincs
ABD-123:2018-08-22:igen:Lada:Nincs
BBC-623:2016-04-22::Lada:Nincs
CAC-523:2018-02-22:igen:Lada:Nincs
ABK-423:2012-04-22:igen:Lada:Nincs
AKG-123:2016-05-22:igen:Lada:Nincs
GBC-123:2015-08-22:igen:Lada:Nincs
checkVehicle.sh
#!/bin/bash
 
FILE=vehicles.txt
 
# DEBUG-hoz:
FIXDATE=2016-03-03
 
DATE=`date "+%Y-%m-%d"`
 
echo $DATE
 
HANYHONAPPAL_ELORE=2
 
 
function checkVehicle() {
    sor=$1
    LEJAR=`echo $sor | awk -F: '{print $2}'`
 
    LEJAR_EV=`echo $LEJAR | awk -F- '{print $1}'`
    AKTUA_EV=`echo $DATE | awk -F- '{print $1}'`
    if [[ "$LEJAR_EV" == "$AKTUA_EV" ]]
    then
	LEJAR_HO=`echo $LEJAR | awk -F- '{print $2}'`
	AKTUA_HO=`echo $DATE | awk -F- '{print $2}'`
	TEMP_HO=`expr $LEJAR_HO - $AKTUA_HO`
	if [[ $TEMP_HO -le $HANYHONAPPAL_ELORE ]]
	then
	    LEJAR_RENDSZAM=`echo $sor | awk -F: '{print $1}'`
	    espeak -vhu "Filgyelem! Lejáró műszaki."
            espeak -vhu "A $LEJAR_RENDSZAM rendszámú gépjármű műszakija ekkor lejár: $LEJAR"
	fi
    fi
 
}
 
cat $FILE | while read sor
do
    ERTESITES=`echo $sor | awk -F: '{print $3}'`
    if [[ "$ERTESITES" == "igen" ]]
    then
	checkVehicle $sor
    fi
done

A set parancs

Sikertelen parancs esetén kilépés:

#!/bin/bash
 
# Ha végrehajtás sikertelen a scriptben, akkor azonnal lépjen ki:
set -e
 
# Ha az aaaaa fájl nem létezik, akkor kilép. 
# Ha nincs set -e, akkor még kiírja a Valami szöveget is. 
 
ls aaaaa
 
echo Valami

Prábluk meg a scriptet végrehajtani set -e használata nélkül is.

Zónafájl felvétele

A Debian GNU/Linux rendszeren a bind démon számára a zónákat a következő helyen kell beállítani:

  • /etc/bind/named.conf.local

Ezek után egy zónafájlt kell készíteni ebbe a könyvtárba:

  • /var/cache/bind/master

Ezt fogjuk automatizálni:

zoneAdd.sh
#!/bin/bash
CONFIG=/etc/bind/named.conf.local
MZONES=/var/cache/bind/master
 
echo -n "Tartománynév: "
read DOMAIN
 
echo -n "IP cím: "
read IP
 
 
ZONEFILE=$DOMAIN.zone
 
cat << EOT >> $CONFIG
zone "$DOMAIN" in {
    type master;
    file "master/$ZONE";
};
EOT
 
cat << EOT >> $MZONES/$ZONEFILE
\$TTL 3D
@     SOA $DOMAIN. hostmaster.$DOMAIN. (
                      2017111701
                      8H
                      2H
                      4W
                      2H)
$DOMAIN.   NS   $DOMAIN.
$DOMAIN.   A    $IP
EOT

Kártyalapok kiíratása

lapok.sh
#!/bin/bash
 
function lap() {
	x=$1
	y=$2
 
    f="\u2660"  # pikk
    tput cup $y $x
	echo -e "\u250c\u2500\u2500\u2510"
	tput cup $((y+1)) $x
	echo -e "\u25026$f\u2502"
	tput cup $((y+2)) $x
	echo -e "\u2514\u2500\u2500\u2518"
}
 
clear
 
lap 5 5
lap 10 5

Az eredmény:

     ┌──┐ ┌──┐
     │6♠│ │6♠│
     └──┘ └──┘

A vonalak:

                u2550   u252c
u250c ┌          ─      ┬           ┐  u2510

u2502 │           

u251c ├                 ┼ u253c     ┤ u2524

u2514 └                 ┴           ┘ u2518  
                        u2534
  • treff (♣) – u2663
  • káró (♦) – u2666
  • kőr (♥) – u2665
  • pikk (♠) – u2660

Külső linkek

oktatas/linux/shell_programozas.1581810010.txt.gz · Utolsó módosítás: 2020/02/16 00:40 szerkesztette: admin