[[oktatas:linux|< Linux]]
====== Shell programozás ======
* **Szerző:** Sallai András
* Copyright (c) 2011, Sallai András
* Szerkesztve: 2011-2021
* Licenc: [[https://creativecommons.org/licenses/by-sa/4.0/|CC BY-SA 4.0]]
* Web: https://szit.hu
===== 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 =====
#!/bin/bash
# egy soros megjegyzés
: '
Több
soros
megjegyzés
'
A (:) kettőspont után szóköz szükséges.
===== 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ő:
#!/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.
===== Escape szekvenciák =====
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
* \0nnn a karakter ASCII kódja nnn (oktálisan)
* \xnnn a karakter ASCII kódja nnn (hexadecimá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!"
LXTerminalban: Szerkesztés > Beállítások > Stílus > Hallható csengőhang [✔]
===== 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é.
===== Változó deklaráció =====
#!/bin/bash
declare -i szam
szam=4
szam=szam+1
szam+=1
echo $szam
#!/bin/bash
declare -i szam=4
szam=szam+1
szam+=1
echo $szam
===== 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
printf "%s\n" alma
printf "%d\n" 35
Szélesség megadása:
printf "%10d\n" 35
Vezető nullák:
printf "%0d\n" 35
printf "%f\n" 35,12345
Tizedesjegyek megadása:
printf "%.2f\n" 35,12345
Egyszerre több:
printf "%010.2f\n" 35,12345
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.
Leghosszabb kiírható számjegy: 1234567890123456789
^ Formátumkód ^ Leírás ^
| d | Egész szám kiíratás |
| f | Valós szám kiíratás |
| s | String kiíratás |
^ Jelző ^ Leírás ^
| 0 | vezető nullák |
| - | balra igazítás |
| + | előjel |
===== 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))
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
===== Kifejezés kiértékelése =====
expr 1 + 3
Az 1+3 összegét, azaz 4-et ad vissza
#!/bin/bash
A=3
B=7
expr $A + $B
#!/bin/bash
A=3
B=7
C=`expr $A + $B`
echo $C
#!/bin/bash
A=3
B=7
C=`expr $A "*" $B`
echo $C
#!/bin/bash
A=3
B=7
C=`expr \( $A "*" $B \) / 2 `
echo $C
#!/bin/bash
A=3
B=7
C=`echo \( $A "*" $B \) / 2 | bc`
echo $C
Gyökvonás:
#!/bin/bash
echo sqrt\(9\) | bc
Hatványozás:
#!/bin/bash
echo 2 ^ 8 | bc
==== Dupla zárójel ====
A következő program a szam változó értéket 1-gyel növeli:
#!/bin/bash
szam=3
szam=$((szam+1))
echo $szam
Variációkat láthatunk a növelésre:
szam=$((szam+1))
((szam=szam+1))
((szam+=1))
((szam++))
==== A let kulcsszó használata ====
#!/bin/bash
szam=3
let "szam=szam+1"
echo $szam
Variációk a let kulcsszó használatára:
let "szam=szam+1"
let "szam+=1"
let "szam++"
let szam=szam+1
let szam+=1
let szam++
==== A bc ====
#!/bin/bash
declare -i szam=4
bc <<< "$szam+2"
#!/bin/bash
declare -i szam=4
echo "$szam+2" | bc
===== 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:
#!/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:
#!/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:
#!/bin/bash
echo -n "Jelszó: "
read -s JELSZO
echo
echo "A beírt jelszó: " $JELSZO
#!/bin/bash
read -p "Jelszó: " -s JELSZO
echo
echo "A beírt jelszó: " $JELSZO
Alapértelmezett szöveg megadása:
#!/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.
===== 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
==== 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 ====
#!/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.
#!/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 ====
Több feltétel is megadható, ha megduplázzuk a szögletes
zárójeleket:
if [[ $num -eq 3 && "$str" == foo ]]
then
# Utasítások
fi
Vagy:
#!/bin/bash
A=0
B=1
if [[ $A -eq 1 || $B -eq 1 ]]
then
echo "Ok"
else
echo "Nem ok"
fi
És:
#!/bin/bash
A=0
B=1
if [[ $A -eq 1 && $B -eq 1 ]]
then
echo "Ok"
else
echo "Nem ok"
fi
Kevert:
#!/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 (( i=0; i<10; i++ ))
do
echo "Helló"
done
#!/bin/bash
for (( i=0; i<10; i++ ))
do
echo $i
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 ====
#!/bin/bash
while read sor
do
echo $sor
done < gy.txt
#!/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:
#!/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 =====
Üres tömb:
tomb=()
Kezdőértéket zárójelek között adhatunk:
tomb=( "egy" "kettő" "három")
A Bash tömb tartalmazhat számokat és karakterláncokat is:
tomb=( 12 "egy" 45 29 "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
#Összes elem:
echo ${tomb[*]}
echo ${tomb[@]}
#Összes index:
echo ${!tomb[*]}
echo ${!tomb[@]}
# Elemek száma:
echo ${#tomb[*]}
echo ${#tomb[@]}
echo ${#tomb[0]} # a 0-dik elem hossza
==== A tömb bejárása ====
#!/bin/bash
ketogenEtelek=(
"Halsaláta"
"Zöldségkör"
"Húsleves"
"Narancs-joghurt"
)
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:
A "*" karakter helyett használhatunk "@" karaktert is.
Szimpla for ciklus használata:
#!/bin/bash
etelek=(
"Halsaláta (uborka, tonhal, tejföl)"
"Zöldségkör (tejföl, túró, zöldségek)"
"Húsleves"
"Narancs joghurt"
)
n=${#etelek[@]}
for (( i=0; i
==== Tömb műveletek ====
Hozzáfűzés
dobasok=(1 5 4)
dobasok+=(7 8)
echo ${dobasok[@]}
Ürítés:
dobasok=()
Tömb része:
echo ${tomb[@]:2:3}
A 2-s indextől szeretnénk, 3 darab karaktert.
Elem törlése:
tomb=(33 49 56 27)
unset tomb[1]
echo ${tomb[@]}
Ha ezek után kiíratjuk a tömb indexeit, ezt kapjuk:
echo ${!tomb[@]}
0 2 3
Hiányzik a 1-s index.
Egész tömb törlése:
unset tomb
==== Deklarált tömb ====
Indexelt tömb:
declare -a szamok
Asszociatív tömb:
declare -A tomb
Indexelt tömb feltöltéssel:
declare -a szamok
szamok+=35
szamok+=47
Asszociatív tömbnek értékadás:
declare -A dolgozo
#egy érék hozzáadása:
dolgozo[fizetes]=3800000
#több érték hozzáadása:
dolgozo=([nev]=János [telepules]=Szolnok)
echo ${dolgozo[nev]}
===== 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)}'
echo "Árvíztűrő" | awk '{print toupper($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 ====
#!/bin/bash
str="alma:körte:barack:szilva"
IFS=':' read -ra tomb <<< "$str"
echo ${tomb[0]}
==== Heredoc szintaxis ====
#!/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
==== Üres sorok törlése ====
cat fajl.txt | sed '/^$/d'
==== Adott karakterek törlése ====
A következő karakterek törlése:
| . ? - , |
cat fajl.txt | sed '/[\.?-\,]//g'
===== 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:
function kiir() {
echo "Helló Világ"
}
kiir
Függvény paraméterrel:
function kiir() {
echo $1
}
kiir "Ezt írd ki"
Bemenő paraméter és visszatérési érték:
#! /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:
#! /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
==== Tömbök ====
Tömb visszatérési érték:
function leker_tomb() {
tomb=(9 4 2 5)
echo ${tomb[@]}
}
a_tomb=($(leker_tomb))
echo "Összes elem: "${tomb[@]}
echo "Mérete: "${#tomb[@]}
===== 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
[ ]
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.
#!/bin/bash
FAJLOK='*.txt'
ls $FAJLOK | while read next_file
do
echo $next_file
done
#!/bin/bash
DIR=/home/utvonal
cd $DIR
for FILE in *
do
echo Könyvtárnevek: $FILE
done
#!/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:
#!/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:
#!/bin/bash
cd /útvonal/könyvtár
cp `ls -t1 *.txt | head -1` /másik/útvonal/könyvtár/
==== Feltöltés FTP-re ====
cd /útvonal/könyvtár
wput ./ ftp://felhasználónév:jelszó@url/könyvtár/
#!/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
#!/bin/sh
USERNAME=jozsi
PASSWORD=titok
HOST_NAME=localhost
LOG=naplo.txt
ftp -n -v $HOST_NAME > $LOG <
#!/bin/sh
USERNAME=jozsi
PASSWORD=titok
HOST_NAME=localhost
LOG=naplo.txt
ftp -n -i -v $HOST_NAME > $LOG <
Így bekéri a jelszót
#!/bin/sh
USERNAME=jozsi
HOST_NAME=localhost
LOG=naplo.txt
ftp -n -i -v $HOST_NAME > $LOG <
#!/bin/sh
USERNAME=jozsi
PASSWORD=titok
HOST_NAME=localhost
LOG=naplo.txt
ftp -n -i -v > $LOG <
Kicsit más:
#!/bin/sh
USERNAME=jozsi
PASSWORD=titok
HOST_NAME=localhost
LOG=naplo.txt
ftp -n -v $HOST_NAME <> $LOG 2>&1
quote user $USERNAME
quote pass $PASSWORD
bin
prompt off
mput *.txt
exit
EOF
==== Dátum ====
=== Dátum darabolása ===
#!/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 ====
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:
for i in {"öt", "négy", "három", "kettő", "egy", "zéró"};do espeak -vhu "$i" && sleep 0.5; done
Ugyanaz kiírva:
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.
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
#!/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óbáljuk 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:
#!/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 ====
#!/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
* További unicode: https://unicode-table.com/hu/
===== Külső linkek =====
* http://tldp.org/LDP/Bash-Beginners-Guide/html/ 2018)
* http://tldp.org/LDP/abs/html/ (Advanced Bash-Scripting Guide; 2018)
* http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO.html (2018)
* http://www.freeos.com/guides/lsst/ch02sec01.html (2018)
* http://www.freeos.com/guides/lsst/ (2018)
* http://user.it.uu.se/~matkin/documents/shell/#simple_commands (2018)
* http://www.arachnoid.com/linux/shell_programming.html (2018)
* http://www.inf.u-szeged.hu/~kato/teaching/unix/unix3.html (2018)
* http://www.arcania.hu/Informatika/linux/commands.html (2018)
* http://www.linuxconfig.org/Bash_scripting_Tutorial (2018)
* http://mywiki.wooledge.org/BashPitfalls (2018)
* http://wiki.koczka.hu/index.php/Kezd%C5%91lap (Operációs rendszerek; 2018)
* http://wiki.bash-hackers.org (2018)
* http://wiki.bash-hackers.org/commands/classictest (2018)
* http://www.comptechdoc.org/os/linux/programming/script/linux_pgscriptintro.html (2018)
* http://www.linuxjournal.com/content/bash-arrays (2018)
* http://www.linuxjournal.com/article/2807 (dialog parancs; 2018)
* http://www.faqs.org/docs/Linux-HOWTO/Bash-Prog-Intro-HOWTO.html (2018)
* http://hup.hu/node/111049 (Hasznos fórum téma; 2018)
* http://www.shelldorado.com/scripts/categories.html (2018)
* http://www.linuxquestions.org/ (2018)
* https://ryanstutorials.net/bash-scripting-tutorial/bash-variables.php (Változók; 2018)
* https://www.linuxjournal.com/content/return-values-bash-functions (2020)
* https://linuxhint.com/return-string-bash-functions/ (2020)
* https://github.com/ruanyf/simple-bash-scripts (2020)