Shell script: mi a célja és hogyan működik a parancsfájl?

A Shell script egy egyszerű szöveges fájl, amely parancsokat tartalmaz a számítógép számára. Segítségével automatizálhatók ismétlődő feladatok, időt és energiát spórolva. A cikk bemutatja, hogyan készíthetünk és futtathatunk ilyen parancsfájlokat könnyedén.
ITSZÓTÁR.hu
55 Min Read
Gyors betekintő

A shell script, vagy magyarul parancsfájl, a Linux, Unix és macOS operációs rendszerek alapvető építőköve, egy rendkívül sokoldalú eszköz, amely lehetővé teszi a felhasználók és rendszergazdák számára, hogy automatizálják az ismétlődő feladatokat, összetett munkafolyamatokat hozzanak létre, és hatékonyabban kezeljék a rendszereket. Lényegében egy szöveges fájlról van szó, amely egy sor parancsot tartalmaz, amelyeket a shell (parancsértelmező) egymás után hajt végre, mintha azokat manuálisan írtuk volna be a terminálba. Ez a rugalmasság és az egyszerűség teszi a shell scripteket nélkülözhetetlenné a modern informatikai környezetben, a szerverek kezelésétől a szoftverfejlesztési folyamatok automatizálásáig.

Mi a shell script és miért van rá szükség?

A shell script egy olyan program, amelyet a shell futtat. A shell maga egy parancsértelmező, egy felhasználói felület, amely lehetővé teszi a felhasználó számára, hogy kommunikáljon az operációs rendszerrel. A leggyakrabban használt shell a Bash (Bourne Again SHell), de léteznek mások is, mint például a Zsh, Ksh, vagy a régi sh. Amikor parancsokat gépelünk be a terminálba, azokat a shell értelmezi és hajtja végre. A shell script lényegében ugyanezt teszi, de egy előre megírt fájlból olvassa be a parancsokat, és automatikusan hajtja végre azokat.

A shell scriptek fő célja az automatizálás. Képzeljük el, hogy minden nap el kell végeznünk ugyanazt a tíz lépésből álló feladatot: fájlok másolása, tömörítése, logfájlok elemzése, adatbázis-mentés indítása, majd az eredmények e-mailben való elküldése. Ha ezt manuálisan tennénk, sok időt és energiát emésztene fel, ráadásul könnyen hibázhatnánk. Egy shell script segítségével ezeket a lépéseket egyszer megírjuk, majd egyetlen paranccsal vagy akár ütemezetten (például cron segítségével) futtathatjuk. Ez nemcsak időt takarít meg, hanem növeli a pontosságot és a konzisztenciát is.

A shell scriptekre számos okból van szükség:

  • Automatizálás: Ismétlődő, monoton feladatok automatizálása, mint például biztonsági mentések, rendszerkarbantartás, naplófájl elemzés.
  • Rendszeradminisztráció: Felhasználók kezelése, szolgáltatások indítása/leállítása, hálózati konfiguráció, erőforrás-felhasználás monitorozása.
  • Fejlesztői munkafolyamatok: Fordítás, tesztelés, telepítés, verziókezelési műveletek automatizálása.
  • Adatfeldolgozás: Szöveges adatok manipulálása, szűrése, átalakítása olyan eszközökkel, mint a grep, sed, awk.
  • Egyszerűség és gyorsaság: Gyorsan lehet velük prototípusokat készíteni, vagy ad-hoc problémákat megoldani anélkül, hogy komplex programozási nyelvre lenne szükség.
  • Interakció az operációs rendszerrel: Közvetlenül hozzáférnek a rendszer parancsaihoz és segédprogramjaihoz.

A shell scriptek tehát hidat képeznek a felhasználó és az operációs rendszer mélyebb funkciói között, lehetővé téve a rendszer erőforrásainak hatékony kihasználását a parancssor erejével.

A shell script működésének alapjai

Egy shell script működése viszonylag egyszerű, de fontos megérteni a mögöttes mechanizmust. Amikor futtatunk egy shell scriptet, a shell (például Bash) elolvassa a fájl tartalmát sorról sorra, és minden sort parancsként értelmez és hajt végre. Ez a folyamat szekvenciális: az egyik parancs befejezése után lép át a következőre, hacsak valamilyen vezérlési szerkezet (pl. if, for) nem írja felül ezt a viselkedést.

Az első és talán legfontosabb elem egy shell scriptben a shebang (ejtsd: sí-bang vagy she-bang) sor. Ez a fájl legelső sora, ami így néz ki:

#!/bin/bash

vagy

#!/usr/bin/env bash

Ez a speciális sor (amely a #! karakterekkel kezdődik, innen a név: hash + bang) tájékoztatja az operációs rendszert, hogy melyik értelmezővel kell futtatni a scriptet. A fenti példákban a /bin/bash vagy a /usr/bin/env bash azt jelzi, hogy a scriptet a Bash shellnek kell feldolgoznia. Ha a shebang sor hiányzik, a scriptet az aktuális felhasználó alapértelmezett shellje fogja megpróbálni futtatni, ami kompatibilitási problémákhoz vezethet, ha a script specifikus Bash (vagy más shell) funkciókat használ.

A script futtatásához általában végrehajtási jogot kell adni neki. Ezt a chmod +x script_neve.sh paranccsal tehetjük meg. Ezután futtatható a ./script_neve.sh paranccsal (a ./ jelzi, hogy az aktuális könyvtárból kell futtatni).

A shell script végrehajtási folyamata a következőképpen zajlik:

  1. Fájl megnyitása: Az operációs rendszer megnyitja a script fájlt.
  2. Shebang értelmezése: Az OS megnézi a shebang sort, és elindítja a megadott értelmezőt (pl. Bash).
  3. Parancsok olvasása és végrehajtása: A shell sorról sorra olvassa a script tartalmát. Minden sorban található parancsot végrehajt, mintha azt közvetlenül a terminálba írtuk volna.
  4. Változók és környezet: A shell script futása során saját környezetet hoz létre, amely tartalmazza a scriptben definiált változókat, függvényeket és az örökölt környezeti változókat.
  5. Kilépési státusz: Minden parancs végrehajtása után egy kilépési státusz (exit status) generálódik. A 0 általában sikeres végrehajtást jelent, míg a nem nulla érték hibát. A scriptekben gyakran ellenőrzik ezt a státuszt a hibakezeléshez.

A shell scriptek ereje abban rejlik, hogy képesek kombinálni a rendszer meglévő parancsait és segédprogramjait (pl. ls, cp, rm, grep, sed, awk) programozási konstrukciókkal, mint például változók, feltételes utasítások, ciklusok és függvények. Ez lehetővé teszi komplex logikák megvalósítását anélkül, hogy alacsonyabb szintű programozási nyelveket (C++, Java, Python) kellene használni.

A shell script felépítése: Alapvető elemek

Egy shell script felépítése egyszerű, de van néhány alapvető elem, amelyeket ismerni kell a hatékony íráshoz.

Shebang sor

Ahogy már említettük, ez a script legelső sora, amely megmondja az operációs rendszernek, melyik értelmezővel kell futtatni a fájlt. Például:

#!/bin/bash

Vagy ha a Bash nem a szokásos helyen van, vagy általánosabb megközelítést szeretnénk:

#!/usr/bin/env bash

Ez utóbbi megkeresi a Bash-t a rendszer PATH változójában, így rugalmasabb.

Kommentek

A kommentek kulcsfontosságúak a script olvashatóságának és karbantarthatóságának szempontjából. A shell scriptekben a # karakterrel kezdődő sorok (a shebang kivételével) kommenteknek minősülnek, és a shell figyelmen kívül hagyja őket végrehajtáskor. Használjuk őket a kód magyarázatára, a célok dokumentálására és a script logikájának megértésének segítésére.

#!/bin/bash
# Ez egy komment. Ez a sor nem fut le.

echo "Hello, világ!" # Ez a parancs kiírja a "Hello, világ!" szöveget.

# Egy összetettebb feladat leírása:
# 1. Ellenőrizzük a fájl létezését.
# 2. Ha létezik, másoljuk egy biztonsági könyvtárba.
# 3. Értesítést küldünk a felhasználónak.

Parancsok

A shell scriptek lényege a parancsok végrehajtása. Bármilyen parancs, amit a terminálba beírhatunk, beírható egy scriptbe is. Ezek lehetnek egyszerű rendszerparancsok, mint az ls, cp, rm, vagy komplexebb segédprogramok, mint a grep, sed, awk, vagy akár más futtatható programok.

#!/bin/bash

# Fájlok listázása
ls -l

# Könyvtár létrehozása
mkdir uj_konyvtar

# Fájl másolása
cp forras.txt uj_konyvtar/cel.txt

# Üzenet kiírása
echo "A script befejeződött."

Sorvégek és többsoros parancsok

Alapértelmezés szerint minden új sor egy új parancsot jelent. Azonban néha szükség lehet arra, hogy egyetlen logikai parancs több fizikai soron keresztül fusson. Ezt a \ (backslash) karakterrel tehetjük meg, ami jelzi a shellnek, hogy a parancs a következő sorban folytatódik.

#!/bin/bash

# Hosszú parancs több sorban
find . -type f -name "*.log" \
    -exec grep -l "hiba" {} \; \
    -print

# Vagy olvashatóbb módon, ha a shell szintaxisa megengedi (pl. zárójelekkel)
if [ -f "valami.txt" ] && \
   [ -s "valami.txt" ]; then
    echo "A fájl létezik és nem üres."
fi

A parancsok pontos és egyértelmű megfogalmazása kulcsfontosságú. A hibásan megírt parancsok váratlan viselkedést okozhatnak, különösen olyan destruktív parancsok esetén, mint az rm vagy mv.

A shell scriptek az operációs rendszer parancssori eszközeinek és a programozási logika elemeinek zseniális ötvözete, amely páratlan rugalmasságot és hatékonyságot biztosít a rendszerfeladatok automatizálásában és az adatok manipulálásában.

Változók és adattípusok a shell scriptekben

A shell változók dinamikusan tárolják az adatokat futás közben.
A shell scriptekben a változók típusa dinamikusan változik, nincs szükség előzetes adattípus-deklarációra.

A változók alapvető fontosságúak bármely programozási nyelvben, így a shell scriptekben is. Lehetővé teszik adatok tárolását és manipulálását a script futása során. A shell scriptekben a változók nem rendelkeznek explicit adattípussal (mint pl. integer, string), minden érték alapvetően stringként kezelődik, bár bizonyos műveletek (pl. matematikai számítások) során a shell megpróbálja számmá konvertálni őket.

Változó deklarálása és értékadás

Változót úgy deklarálunk és adunk neki értéket, hogy a változó nevét közvetlenül az = jel elé írjuk, szóköz nélkül. Az érték lehet egy string, egy szám, vagy egy másik parancs kimenete.

#!/bin/bash

nev="Péter"
kor=30
uzenet="Hello, $nev! Te $kor éves vagy."

echo $uzenet
# Kimenet: Hello, Péter! Te 30 éves vagy.

Fontos: A változó neve és az = jel között nem lehet szóköz! Az értékadásnál az idézőjelek használata javasolt, ha az érték szóközt tartalmaz, vagy speciális karaktereket (pl. *, $, !) tartalmazhat, hogy elkerüljük a shell értelmezési hibáit.

Változók hivatkozása

Egy változó értékére a $ előtaggal hivatkozunk. A legjobb gyakorlat a változó nevének kapcsos zárójelekbe (${változó}) tétele, különösen akkor, ha a változó közvetlenül más karakterekkel van körülvéve, és a shellnek egyértelműen meg kell különböztetnie a változó nevét.

#!/bin/bash

fajlnev="dokumentum"
kiterjesztes=".txt"

# Rossz: A shell nem tudja, hogy a fajlnev_backup egy változó, vagy a fajlnevhez tartozó része
# echo $fajlnev_backup

# Jó: Egyértelműen jelöli a változó végét
echo "A fájl neve: ${fajlnev}${kiterjesztes}"
# Kimenet: A fájl neve: dokumentum.txt

Környezeti változók

A környezeti változók olyan változók, amelyek a shell környezetében léteznek, és az összes alfolyamat számára elérhetők. Ezeket gyakran használják rendszerkonfigurációk, elérési útvonalak (PATH), felhasználói adatok (HOME, USER) tárolására. Az export paranccsal tehetünk egy változót környezeti változóvá.

#!/bin/bash

# Helyi változó
my_var="Ez egy helyi változó"
echo "Helyi változó: $my_var"

# Környezeti változó
export MY_ENV_VAR="Ez egy környezeti változó"
echo "Környezeti változó: $MY_ENV_VAR"

# Egy alfolyamatban is elérhető lesz
bash -c 'echo "Alfolyamatban: $MY_ENV_VAR"'

Speciális változók

A shell számos speciális változót biztosít, amelyek információt tartalmaznak a script futásáról vagy a parancssori argumentumokról:

  • $0: A script neve.
  • $1, $2, …: Az első, második, stb. parancssori argumentum.
  • $#: A parancssori argumentumok száma.
  • $*: Az összes parancssori argumentum egyetlen stringként, szóközzel elválasztva.
  • $@: Az összes parancssori argumentum különálló stringekként. Ideális ciklusokhoz.
  • $?: Az utoljára végrehajtott parancs kilépési státusza (0 sikeres, nem 0 hiba).
  • $$: A script folyamatazonosítója (PID).
  • $!: Az utoljára háttérben futtatott parancs PID-je.
#!/bin/bash

echo "A script neve: $0"
echo "Argumentumok száma: $#"
echo "Összes argumentum (*): $*"
echo "Összes argumentum (@): $@" # Fontos különbség a for ciklusnál!

echo "Első argumentum: $1"
echo "Második argumentum: $2"

ls /nemletezo_konyvtar
echo "Az 'ls' parancs kilépési státusza: $?"

A változók megfelelő használata elengedhetetlen a dinamikus és rugalmas scriptek írásához. Lehetővé teszi, hogy a scriptek interaktívak legyenek, felhasználói bemenetre reagáljanak, és különböző környezetekben is működjenek.

Bemenet és kimenet kezelése

A shell scriptek gyakran interakcióba lépnek a felhasználóval, vagy adatokat olvasnak be fájlokból, és eredményeket írnak ki a képernyőre vagy fájlokba. Ennek kezelésére szolgálnak a bemeneti és kimeneti parancsok, valamint az átirányítások.

Kimenet: echo és printf

A leggyakoribb parancs a kimenet képernyőre írására az echo. Egyszerű stringek, változók vagy parancsok kimenetének megjelenítésére szolgál.

#!/bin/bash

nev="Anna"
echo "Szia, $nev!"
echo "A mai dátum: $(date)" # Parancs kimenetének beillesztése

Az echo alapértelmezetten új sort ad hozzá a végére. Az -n opcióval elhagyható az új sor, az -e opcióval pedig értelmezhetők az escape szekvenciák (pl. \n új sor, \t tabulátor).

#!/bin/bash

echo -n "Ez egy sor, "
echo "ez pedig a folytatása."

echo -e "Első sor.\nMásodik sor.\tTabulátor."

A printf parancs fejlettebb kimeneti formázást tesz lehetővé, hasonlóan a C nyelv printf függvényéhez. Különösen hasznos, ha pontosan formázott oszlopos kimenetre vagy számok formázására van szükség.

#!/bin/bash

termek="Laptop"
ar=1200.50
darab=3

printf "Termék: %s\nÁr: %.2f EUR\nDarab: %d\nÖsszesen: %.2f EUR\n" "$termek" "$ar" "$darab" "$(echo "$ar * $darab" | bc)"

A printf nem ad hozzá új sort a végére alapértelmezetten, azt expliciten kell jelezni \n-nel.

Bemenet: read

A read parancs lehetővé teszi a felhasználói bemenet beolvasását a billentyűzetről. Az olvasott értéket egy változóba menti.

#!/bin/bash

echo "Kérlek add meg a neved:"
read felhasznalo_nev

echo "Szia, $felhasznalo_nev! Üdv a scriptben."

A read parancsnak számos hasznos opciója van:

  • -p "Prompt szöveg": Kiír egy prompt üzenetet a bemenet előtt.
  • -s: Elrejti a beírt karaktereket (jelszavakhoz ideális).
  • -t idő: Időkorlátot állít be a bemenetre (másodpercben).
  • -r: Nyers bemenetet olvas be, figyelmen kívül hagyva a backslash escape-eket.
#!/bin/bash

read -p "Add meg a felhasználóneved: " username
read -s -p "Add meg a jelszavad: " password
echo # Új sor a jelszó beolvasása után

echo "Felhasználónév: $username"
echo "Jelszó (titkosítva): $password"

Bemeneti/Kimeneti átirányítás

A shell egyik legerősebb funkciója a bemeneti és kimeneti átirányítás. Ez lehetővé teszi a parancsok kimenetének fájlba írását, vagy egy fájl tartalmának bemenetként való használatát egy parancs számára.

  • >: Kimenet átirányítása fájlba. Ha a fájl létezik, felülírja.
  • >>: Kimenet hozzáfűzése fájlhoz. Ha a fájl létezik, a végére ír, ha nem, létrehozza.
  • <: Bemenet átirányítása fájlból.
  • 2>: Hibaüzenetek (stderr) átirányítása fájlba.
  • &> vagy >&: Standard kimenet (stdout) és hibaüzenetek (stderr) együttes átirányítása fájlba.
#!/bin/bash

# Kimenet fájlba írása (felülírja)
ls -l > fajl_lista.txt

# Kimenet hozzáfűzése fájlhoz
echo "Ez egy új sor." >> fajl_lista.txt

# Fájl tartalmának beolvasása parancsba
wc -l < fajl_lista.txt # megszámolja a sorokat a fájlban

# Hibaüzenetek átirányítása
rm nem_letezo_fajl 2> hibalog.txt

# Standard kimenet és hibaüzenetek együttes átirányítása
find /etc -name "*.conf" &> osszes_kimenet.txt

Pipe-ok (|)

A pipe (csővezeték) lehetővé teszi az egyik parancs standard kimenetének (stdout) közvetlen átirányítását egy másik parancs standard bemenetére (stdin). Ez rendkívül erőteljes, és lehetővé teszi a komplex adatfeldolgozási láncok felépítését.

#!/bin/bash

# Fájlok listázása, majd szűrés "log" szóra, majd sorok számlálása
ls -l | grep "log" | wc -l

# Rendszerfolyamatok listázása, szűrés "apache" szóra, majd a második oszlop (PID) kiírása
ps aux | grep apache | awk '{print $2}'

A bemeneti és kimeneti kezelés, valamint az átirányítások és pipe-ok ismerete alapvető a shell scriptek hatékony írásához. Ezek segítségével a scriptek interaktívvá válnak, képesek adatokat feldolgozni, és automatizált munkafolyamatokba illeszthetők.

Vezérlési szerkezetek: Döntések és elágazások

A shell scriptek nem lennének sokkal többet, mint egyszerű parancslisták, ha nem lennének bennük vezérlési szerkezetek. Ezek teszik lehetővé, hogy a scriptek döntéseket hozzanak, különböző útvonalakon haladjanak a feltételek alapján, és ismétlődő feladatokat végezzenek. A legfontosabb döntéshozatali szerkezetek az if és a case.

if-elif-else szerkezet

Az if utasítás a leggyakoribb módja a feltételes végrehajtásnak. Egy feltételt ellenőriz, és ha az igaz, végrehajt egy kódrészletet. Az elif (else if) és az else opcionális, és további feltételeket vagy egy alapértelmezett ágat biztosítanak.

#!/bin/bash

szam=10

if [ "$szam" -gt 5 ]; then
    echo "A szám nagyobb, mint 5."
elif [ "$szam" -eq 5 ]; then
    echo "A szám pontosan 5."
else
    echo "A szám kisebb, mint 5."
fi

A feltételek ellenőrzésére a test parancsot vagy annak rövidített formáját, a [ ]-t használjuk. A Bash (és más modern shellek) emellett fejlettebb feltételeket is támogat a [[ ]] és a (( )) szintaxissal.

Gyakori feltételek ([ feltétel ] vagy test feltétel):

  • Számok összehasonlítása:
    • -eq: egyenlő (equal)
    • -ne: nem egyenlő (not equal)
    • -gt: nagyobb, mint (greater than)
    • -ge: nagyobb vagy egyenlő (greater than or equal)
    • -lt: kisebb, mint (less than)
    • -le: kisebb vagy egyenlő (less than or equal)
  • Stringek összehasonlítása:
    • = vagy ==: egyenlő
    • !=: nem egyenlő
    • -z "string": string üres (zero length)
    • -n "string": string nem üres (non-zero length)
  • Fájlok ellenőrzése:
    • -e fájl: fájl létezik
    • -f fájl: fájl létezik és reguláris fájl
    • -d könyvtár: könyvtár létezik és könyvtár
    • -s fájl: fájl létezik és nem üres (non-zero size)
    • -r fájl: fájl olvasható
    • -w fájl: fájl írható
    • -x fájl: fájl végrehajtható

Példa fájl ellenőrzésre:

#!/bin/bash

fajl="naplo.log"

if [ -f "$fajl" ]; then
    echo "A $fajl létezik és reguláris fájl."
    if [ -s "$fajl" ]; then
        echo "A $fajl nem üres."
    else
        echo "A $fajl üres."
    fi
else
    echo "A $fajl nem létezik vagy nem reguláris fájl."
fi

Logikai operátorok:
A feltételeket kombinálhatjuk logikai operátorokkal:

  • -a vagy &&: ÉS (and)
  • -o vagy ||: VAGY (or)
  • !: NEM (not)
#!/bin/bash

kor=20
nem="férfi"

if [ "$kor" -ge 18 ] && [ "$nem" = "férfi" ]; then
    echo "Felnőtt férfi."
fi

if [ "$kor" -lt 18 ] || [ "$nem" = "nő" ]; then
    echo "Kiskorú vagy nő."
fi

case szerkezet

A case utasítás egy alternatíva az if-elif-else láncolatra, ha több lehetséges értéket kell ellenőrizni egyetlen változó alapján. Különösen hasznos menürendszerek vagy argumentumok feldolgozásakor.

#!/bin/bash

read -p "Válassz egy opciót (a/b/c): " opcio

case "$opcio" in
    a|A) # Több minta is megadható | jellel
        echo "Az 'A' opciót választottad."
        ;; # Minden ágat ezzel zárjuk
    b|B)
        echo "A 'B' opciót választottad."
        ;;
    c|C)
        echo "A 'C' opciót választottad."
        ;;
    *) # Alapértelmezett ág, ha egyik sem illeszkedik
        echo "Érvénytelen opció."
        ;;
esac

A case szerkezet mintákat (pattern) használ az összehasonlításhoz, ami rugalmasabbá teszi, mint a if egyenlőségvizsgálata. Használhatók benne glob (wildcard) karakterek, mint a * (bármilyen karakterek bármilyen száma) és a ? (bármilyen egyetlen karakter).

#!/bin/bash

fajlnev="kep.jpg"

case "$fajlnev" in
    *.txt)
        echo "Ez egy szöveges fájl."
        ;;
    *.jpg|*.png|*.gif)
        echo "Ez egy képfájl."
        ;;
    *)
        echo "Ismeretlen fájltípus."
        ;;
esac

A vezérlési szerkezetek nélkülözhetetlenek a dinamikus és intelligens shell scriptek írásához, amelyek képesek alkalmazkodni a különböző körülményekhez és felhasználói bemenetekhez.

Ciklusok: Ismétlődő feladatok automatizálása

A ciklusok a programozás alapvető elemei, amelyek lehetővé teszik egy kódrészlet ismételt végrehajtását, amíg egy bizonyos feltétel teljesül, vagy egy elemek listáján végigmegyünk. A shell scriptekben a leggyakoribb ciklusok a for, a while és az until.

for ciklus

A for ciklus a leggyakrabban használt ciklustípus, amikor egy ismert listán (fájlok, stringek, számok) szeretnénk végigmenni. Két fő szintaxisa van:

1. Lista alapú for ciklus (Bash stílus)

Ez a leggyakoribb forma, amely egy elemek listáján iterál végig. Minden iterációban a lista következő eleme hozzárendelődik a ciklus változójához.

#!/bin/bash

# Fájlok feldolgozása
echo "Fájlok listázása az aktuális könyvtárban:"
for fajl in *.txt; do # Iterál a .txt kiterjesztésű fájlokon
    echo "Feldolgozom: $fajl"
    # Itt lehetne parancsokat végrehajtani a fájllal, pl. cat "$fajl"
done

# Stringek listáján iterálás
gyumolcsok="alma körte szilva"
echo "Kedvenc gyümölcseim:"
for gyumolcs in $gyumolcsok; do
    echo "- $gyumolcs"
done

# Parancssori argumentumokon iterálás (fontos: "$@")
echo "Feldolgozom az argumentumokat:"
for arg in "$@"; do
    echo "Argumentum: $arg"
done

Fontos: Amikor parancssori argumentumokon iterálunk, vagy változókat tartalmazó listán, mindig használjuk a duplá idézőjeleket ("$@" vagy "$valtozo"), hogy elkerüljük a szótagolási (word splitting) és glob (pathname expansion) problémákat, különösen, ha az elemek szóközt tartalmaznak.

2. C-stílusú for ciklus (Bash)

Ez a forma ismerősebb lehet más programozási nyelvekből, ahol egy számláló változót használunk a ciklus szabályozására. A szintaxis: for (( inicializálás; feltétel; lépés )); do ... done.

#!/bin/bash

echo "Számolás 1-től 5-ig:"
for (( i=1; i<=5; i++ )); do
    echo "Szám: $i"
done

echo "Páros számok 10-től 2-ig:"
for (( i=10; i>=2; i-=2 )); do
    echo "Páros szám: $i"
done

while ciklus

A while ciklus mindaddig fut, amíg a megadott feltétel igaz. Ez hasznos, ha nem tudjuk előre a ciklusok számát, például addig olvasunk egy fájlból, amíg van benne tartalom, vagy addig várunk, amíg egy szolgáltatás elindul.

#!/bin/bash

szamlalo=0
while [ "$szamlalo" -lt 5 ]; do
    echo "Számláló: $szamlalo"
    szamlalo=$((szamlalo + 1)) # Matematikai művelet
    sleep 1 # Várakozás 1 másodpercet
done

echo "Ciklus vége."

Példa fájl sorainak olvasására:

#!/bin/bash

fajl="lista.txt"

# Hozzunk létre egy tesztfájlt
echo "Első sor" > "$fajl"
echo "Második sor" >> "$fajl"
echo "Harmadik sor" >> "$fajl"

echo "Fájl tartalmának soronkénti olvasása:"
while IFS= read -r sor; do
    echo "Tartalom: $sor"
done < "$fajl" # A fájl átirányítása a while ciklus bemenetére

A IFS= read -r sor egy gyakori és robusztus módja a fájlok soronkénti olvasásának. Az IFS= megakadályozza a szótagolást, a -r pedig a backslash escape-ek értelmezését.

until ciklus

Az until ciklus ellentétesen működik a while ciklussal: mindaddig fut, amíg a feltétel hamis. Amint a feltétel igazzá válik, a ciklus leáll.

#!/bin/bash

# Várakozás, amíg egy fájl létezni nem kezd
fajl="figyelt_fajl.txt"
echo "Várakozás a '$fajl' fájlra..."

until [ -f "$fajl" ]; do
    echo "A fájl még nem létezik. Várakozás..."
    sleep 2
done

echo "A '$fajl' fájl létrejött! Folytatom."

break és continue

  • break: Azonnal kilép a legbelső ciklusból.
  • continue: Kihagyja a ciklus aktuális iterációjának hátralévő részét, és a következő iterációra lép.
#!/bin/bash

for i in {1..10}; do
    if [ "$i" -eq 5 ]; then
        echo "Megtaláltam az 5-öt, kilépek."
        break
    fi
    echo "Aktuális szám: $i"
done

echo "---"

for i in {1..10}; do
    if (( i % 2 == 0 )); then
        echo "Páros szám ($i), kihagyom."
        continue
    fi
    echo "Páratlan szám: $i"
done

A ciklusok elsajátítása kulcsfontosságú a shell scriptek írásakor, mivel ezek teszik lehetővé az ismétlődő és időigényes feladatok hatékony automatizálását, ezzel óriási időt és energiát takarítva meg a felhasználóknak és rendszergazdáknak.

Függvények: Kód újrafelhasználása és modularitás

A függvények növelik a shell szkriptek átláthatóságát és újrahasználhatóságát.
A függvények lehetővé teszik a kód újrafelhasználását és a parancsfájl átláthatóbb, modulárisabb felépítését.

Ahogy a scriptek egyre hosszabbak és komplexebbek lesznek, fontos, hogy a kódot modulárisan és újrafelhasználhatóan szervezzük. Erre szolgálnak a függvények. Egy függvény egy elnevezett kódrészlet, amelyet többször is meghívhatunk a scripten belül, elkerülve a kódismétlést és javítva az olvashatóságot.

Függvény deklarálása és hívása

A függvényeket kétféleképpen deklarálhatjuk Bash-ben:

#!/bin/bash

# 1. Szintaxis (a preferált, POSIX-kompatibilis)
function udvozles {
    echo "Szia, $1!" # $1 az első argumentum
}

# 2. Szintaxis (Bash-specifikus)
koszontes() {
    echo "Üdvözöllek, $1!"
}

# Függvény hívása
udvozles "Péter"
koszontes "Anna"

A függvényeket a nevükkel hívhatjuk meg, akárcsak egy parancsot. Az argumentumokat szóközzel elválasztva adhatjuk át, és a függvényen belül a $1, $2, stb. speciális változókkal érhetjük el őket, akárcsak a script parancssori argumentumait. A $# a függvénynek átadott argumentumok számát, a $@ pedig az összes argumentumot jelöli.

Függvények argumentumai és visszatérési értékei

A függvények a return paranccsal adhatnak vissza egy kilépési státuszt (0-255 közötti számot), akárcsak a normál parancsok. A 0 általában sikert, a nem nulla érték hibát jelez. A visszatérési értékre a $? változóval hivatkozhatunk a függvény hívása után.

Ha egy függvényből szöveges kimenetet szeretnénk kapni, azt általában a echo paranccsal tesszük, majd a függvény hívását egy parancssubstitúcióban ($(függvény)) használjuk.

#!/bin/bash

# Függvény kilépési státusszal
ellenoriz_fajl() {
    local fajl="$1" # local kulcsszó: változó a függvényen belül marad
    if [ -f "$fajl" ]; then
        echo "A '$fajl' létezik."
        return 0 # Sikeres
    else
        echo "A '$fajl' nem létezik."
        return 1 # Hiba
    fi
}

# Függvény szöveges kimenettel
get_current_time() {
    date +"%Y-%m-%d %H:%M:%S"
}

# Függvények hívása és visszatérési értékek kezelése
ellenoriz_fajl "nemletezo.txt"
if [ $? -eq 0 ]; then
    echo "Ellenőrzés sikeres."
else
    echo "Ellenőrzés sikertelen."
fi

aktualis_ido=$(get_current_time)
echo "Aktuális idő: $aktualis_ido"

Fontos: A local kulcsszó használata javasolt a függvényen belüli változók deklarálásakor, hogy elkerüljük a globális változók véletlen felülírását és a névütközéseket. Ez hozzájárul a függvények reusability-jéhez.

Függvények előnyei

  • Kód újrafelhasználása: Ugyanazt a kódot többször is felhasználhatjuk anélkül, hogy újraírnánk.
  • Modularitás: A kódot logikai egységekre bonthatjuk, ami javítja az olvashatóságot és a karbantarthatóságot.
  • Hibakeresés: Könnyebb megtalálni és javítani a hibákat, ha a kód kisebb, jól definiált egységekre van bontva.
  • Absztrakció: Elrejthetjük a komplex részleteket egy egyszerű függvényhívás mögé.

A függvények elengedhetetlenek a komplex shell scriptek strukturálásához és kezeléséhez. Segítségükkel a scriptek tisztábbá, hatékonyabbá és könnyebben fejleszthetővé válnak.

Parancssori argumentumok és paraméterek kezelése

A shell scriptek gyakran igénylik, hogy a felhasználó adatokat adjon meg a futtatáskor, vagy hogy különböző opciókkal indíthatók legyenek. Erre szolgálnak a parancssori argumentumok. Ezeket a script neve után, szóközzel elválasztva adjuk meg a terminálban.

Alapvető argumentumok kezelése

Ahogy a speciális változóknál már említettük, a parancssori argumentumokat a $1, $2, $3, stb. változókkal érhetjük el, ahol $1 az első argumentum, $2 a második, és így tovább. A $0 a script nevét tartalmazza.

#!/bin/bash
# script_nev.sh

echo "A script neve: $0"
echo "Az első argumentum: $1"
echo "A második argumentum: $2"
echo "A harmadik argumentum: $3"

# Példa futtatás: ./script_nev.sh alma körte szilva
# Kimenet:
# A script neve: ./script_nev.sh
# Az első argumentum: alma
# A második argumentum: körte
# A harmadik argumentum: szilva

A $# változó tartalmazza az átadott argumentumok számát, ami hasznos lehet annak ellenőrzésére, hogy a felhasználó megadott-e elegendő argumentumot.

#!/bin/bash

if [ "$#" -ne 2 ]; then
    echo "Használat: $0 <forrás_fájl> <cél_könyvtár>"
    exit 1 # Kilépés hibával
fi

forras_fajl="$1"
cel_konyvtar="$2"

if [ ! -f "$forras_fajl" ]; then
    echo "Hiba: A forrásfájl '$forras_fajl' nem létezik."
    exit 1
fi

if [ ! -d "$cel_konyvtar" ]; then
    echo "Hiba: A célkönyvtár '$cel_konyvtar' nem létezik."
    exit 1
fi

cp "$forras_fajl" "$cel_konyvtar"
echo "A '$forras_fajl' sikeresen átmásolva ide: '$cel_konyvtar'."

A $* és $@ speciális változók az összes argumentumot tartalmazzák. Bár hasonlóak, van egy fontos különbség, amikor idézőjelek közé tesszük őket:

  • "$*": Az összes argumentumot egyetlen stringként kezeli, szóközzel elválasztva.
  • "$@": Az összes argumentumot különálló stringekként kezeli. Ez a preferált forma, ha argumentumokon szeretnénk iterálni, különösen, ha azok szóközt tartalmaznak.
#!/bin/bash

echo "Futtatás: $0 \"alma körte\" szilva"

echo "--- \$* példa ---"
for arg in "$*"; do
    echo "Arg: $arg"
done
# Kimenet: Arg: alma körte szilva (egy sorban)

echo "--- \$@ példa ---"
for arg in "$@"; do
    echo "Arg: $arg"
done
# Kimenet:
# Arg: alma körte
# Arg: szilva (külön sorban)

Opciók (flags) kezelése: getopts

Komplexebb scriptek esetén gyakran szükség van opciók (pl. -v a verbose módhoz, -f a fájlnévhez) kezelésére. Erre a célra a getopts beépített parancs a legrobosztusabb megoldás.

#!/bin/bash

VERBOSE=false
OUTPUT_FILE=""

while getopts "vf:" opt; do
    case ${opt} in
        v )
            VERBOSE=true
            ;;
        f )
            OUTPUT_FILE="$OPTARG"
            ;;
        \? ) # Érvénytelen opció
            echo "Használat: $0 [-v] [-f <fájlnév>] <argumentumok...>"
            exit 1
            ;;
    esac
done

# Shifteljük el a feldolgozott opciókat, hogy a maradék argumentumok elérhetők legyenek $1, $2, stb.
shift $((OPTIND -1))

echo "Részletes mód: $VERBOSE"
echo "Kimeneti fájl: ${OUTPUT_FILE:-\"Nincs megadva\"}" # Ha üres, írja ki "Nincs megadva"
echo "Feldolgozandó argumentumok:"
for arg in "$@"; do
    echo "- $arg"
done

# Példa futtatás: ./script.sh -v -f log.txt arg1 "második arg"

A getopts használata:

  • Az első argumentum egy string, amely tartalmazza az összes elfogadott opciót. Ha egy opció után kettőspont (:) van, az azt jelenti, hogy az adott opcióhoz argumentum is tartozik.
  • A while ciklus mindaddig fut, amíg a getopts további opciókat talál.
  • A feldolgozott opció a $opt változóban található.
  • Az opcióhoz tartozó argumentum (ha van) az $OPTARG változóban található.
  • Az $OPTIND változó a következő feldolgozandó argumentum indexét tárolja. A shift $((OPTIND -1)) paranccsal eltávolítjuk a már feldolgozott opciókat, így a fennmaradó argumentumok a $1, $2, stb. helyekre kerülnek.

A parancssori argumentumok és opciók kezelése kulcsfontosságú ahhoz, hogy a scriptek rugalmasak és felhasználóbarátok legyenek, lehetővé téve a testreszabott viselkedést a különböző futtatások során.

Hibakezelés és hibakeresés a shell scriptekben

A robusztus shell scriptek írásának elengedhetetlen része a hibák megfelelő kezelése és a problémák hatékony felderítése. Egy jól megírt script nemcsak azt teszi, amit elvárnak tőle, hanem azt is kezeli, ha valami rosszul sül el.

Hibakezelés

Kilépési státusz ellenőrzése ($?)

Minden parancs végrehajtása után egy kilépési státuszt (exit status) ad vissza. A 0 érték általában sikert jelez, míg a nem nulla érték (1-255) valamilyen hibát. Ezt a státuszt a $? speciális változóban tárolja a shell.

#!/bin/bash

cp nemletezo_fajl.txt uj_hely.txt
if [ $? -ne 0 ]; then
    echo "Hiba: A fájl másolása sikertelen volt."
    exit 1 # Kilépés hibakóddal
fi
echo "Fájl másolása sikeres."

set -e: Kilépés hibára

Ez az egyik leghasznosabb opció a shell scriptekben. Ha a set -e (vagy set -o errexit) opciót beállítjuk a script elején, a script azonnal kilép, ha bármelyik parancs hibával (nem nulla kilépési státusszal) tér vissza. Ez megakadályozza, hogy a script hibás állapotban tovább fusson, és további problémákat okozzon.

#!/bin/bash
set -e # Ha bármely parancs hibával tér vissza, a script azonnal kilép

echo "Ez az első parancs."
cp nemletezo_fajl.txt /tmp/cel.txt # Ez a parancs hibát okoz

echo "Ez a sor sosem fog megjelenni, ha a másolás sikertelen volt."

Fontos: A set -e nem reagál a pipe-okban lévő hibákra, csak az utolsó parancs hibájára. A set -o pipefail opcióval orvosolható ez a probléma, így a pipe bármelyik parancsának hibája esetén az egész pipe hibával tér vissza.

#!/bin/bash
set -e
set -o pipefail # A pipe-okban lévő hibák is kilépést okoznak

echo "Ez egy teszt" | grep "nemlétező_szó"
echo "Ez a sor sem fog megjelenni."

trap parancs

A trap parancs lehetővé teszi, hogy bizonyos események (jelek) bekövetkeztekor (pl. script leállítása, hiba) egy adott parancsot vagy függvényt futtassunk. Gyakori használata a tisztítási feladatok (ideiglenes fájlok törlése) végrehajtása kilépéskor.

#!/bin/bash

# Függvény, ami lefut, ha a script kilép (akár hibával, akár sikerrel)
cleanup() {
    echo "Tisztítás végrehajtása..."
    rm -f /tmp/temp_file_*.txt
}

# A cleanup függvény futtatása EXIT jel esetén (kilépéskor)
trap cleanup EXIT

# A cleanup függvény futtatása ERR jel esetén (hiba esetén)
trap 'echo "Hiba történt a(z) $LINENO sorban!"; cleanup; exit 1' ERR

echo "Ideiglenes fájl létrehozása..."
touch /tmp/temp_file_1.txt
touch /tmp/temp_file_2.txt

echo "Valamilyen művelet..."
ls -l /nemletezo_konyvtar # Ez hibát okoz, és elindítja az ERR trap-et

echo "Ez a sor nem fog lefutni hiba esetén."

Hibakeresés (Debugging)

set -x: Parancsok kiírása

A set -x (vagy set -o xtrace) opció bekapcsolja a "trace" módot, ami minden végrehajtott parancsot kiír a terminálra, mielőtt az lefutna. Ez rendkívül hasznos a script futásának követésére és a problémás sorok azonosítására.

#!/bin/bash
# set -x # Bekapcsolhatjuk itt, vagy futtathatjuk bash -x script.sh formában

nev="János"
echo "Szia, $nev!"

if [ -d "/tmp" ]; then
    echo "A /tmp könyvtár létezik."
else
    echo "A /tmp könyvtár nem létezik."
fi

A kimenet minden egyes parancs előtt egy + jellel jelzi a végrehajtást, és kiírja a parancsot a változók feloldott értékeivel.

set -v: Bemeneti sorok kiírása

A set -v (vagy set -o verbose) opció kiírja a script minden sorát, ahogy azt a shell olvassa, még a kommenteket is. Kevésbé hasznos, mint a set -x, de segíthet a szintaktikai hibák felderítésében.

Részleges hibakeresés

A hibakeresési opciókat be- és kikapcsolhatjuk a script különböző részein, hogy csak a problémás területekre fókuszáljunk:

#!/bin/bash

echo "Ez a rész normálisan fut."

set -x # Hibakeresés bekapcsolása
echo "Ez a rész trace módban fut."
ls -l /tmp
set +x # Hibakeresés kikapcsolása

echo "Ez a rész ismét normálisan fut."

echo és printf a hibakereséshez

A legegyszerűbb, de gyakran leghatékonyabb hibakeresési módszer az echo vagy printf parancsok beillesztése a scriptbe, hogy kiírjuk a változók értékeit, vagy jelezzük, melyik kódrészlet futott le.

#!/bin/bash

fajl="adataim.txt"

echo "DEBUG: A fájlnév változó értéke: '$fajl'"

if [ -f "$fajl" ]; then
    echo "DEBUG: A fájl létezik, feldolgozás indítása..."
    # ... feldolgozási logika ...
else
    echo "DEBUG: A fájl nem létezik, kilépés."
    exit 1
fi

A hibakezelés és hibakeresés integrálása a shell script fejlesztési folyamatába elengedhetetlen a megbízható és fenntartható scriptek létrehozásához. Segítenek azonosítani és orvosolni a problémákat, mielőtt azok komolyabb károkat okoznának.

Gyakori és haladó parancsok a shell scriptekben

A shell scriptek ereje abban rejlik, hogy képesek integrálni és automatizálni a Linux/Unix rendszerekben elérhető parancsok és segédprogramok széles skáláját. Néhány parancs különösen gyakran és hatékonyan használható scriptekben az adatfeldolgozásra, fájlkezelésre és rendszerinterakcióra.

grep: Szöveges minták keresése

A grep (Global Regular Expression Print) parancs egy sorban keres egy adott mintát, és kiírja azokat a sorokat, amelyek tartalmazzák a mintát. Rendkívül hasznos naplófájlok elemzésére, konfigurációs fájlok szűrésére stb.

#!/bin/bash

# Keresés a "hiba" szó után egy naplófájlban
grep "hiba" /var/log/syslog

# Esetérzéketlen keresés és sorok számlálása
grep -i "error" /var/log/messages | wc -l

# Sorok kiírása, amelyek NEM tartalmazzák a mintát
grep -v "info" /var/log/auth.log

# Rekurzív keresés fájlokban
grep -r "TODO" .

Gyakori opciók: -i (esetérzéketlen), -v (invertálja a találatokat), -c (csak a sorok számát adja vissza), -n (sorok számát is kiírja), -r (rekurzív keresés könyvtárakban), -l (csak a fájlneveket írja ki, ahol talált).

sed: Szövegstream szerkesztő

A sed (Stream EDitor) egy rendkívül erőteljes parancs szöveges fájlok vagy bemeneti streamek manipulálására. Gyakran használják szöveg cseréjére, sorok törlésére, beszúrására vagy kinyerésére.

#!/bin/bash

# Szöveg cseréje (első előfordulás soronként)
echo "Hello World" | sed 's/World/Universe/'
# Kimenet: Hello Universe

# Szöveg cseréje (összes előfordulás soronként)
echo "alma, körte, alma" | sed 's/alma/banán/g'
# Kimenet: banán, körte, banán

# Sor törlése, ami tartalmazza a mintát
sed '/hiba/d' /var/log/alkalmazas.log

# Sor beszúrása az 5. sor elé
sed '5i\--- EZ EGY ÚJ SOR ---' bemenet.txt

# In-place szerkesztés (vigyázat!)
# sed -i 's/régi/új/g' fajl.txt

A sed a reguláris kifejezések széles skáláját támogatja, ami rendkívül rugalmassá teszi a mintakeresésben és cserében.

awk: Mintakereső és feldolgozó nyelv

Az awk egy programozási nyelv, amelyet kifejezetten szöveges adatok feldolgozására terveztek. Soronként dolgozza fel a bemenetet, és minden sort mezőkre (alapértelmezés szerint szóközzel elválasztva) bont. Nagyon hasznos táblázatos adatok elemzésére.

#!/bin/bash

# Teszt adatfájl létrehozása
echo "Név Kor Város" > adatok.txt
echo "Péter 30 Budapest" >> adatok.txt
echo "Anna 25 Szeged" >> adatok.txt
echo "Gábor 35 Debrecen" >> adatok.txt

# Kiírja a második oszlopot (Kor)
awk '{print $2}' adatok.txt
# Kimenet:
# Kor
# 30
# 25
# 35

# Kiírja azokat a sorokat, ahol a kor > 30
awk '$2 > 30 {print $1, $2}' adatok.txt
# Kimenet:
# Gábor 35

# Összegzés
ls -l | awk '{sum += $5} END {print "Összes méret: " sum " byte"}'

Az awk a BEGIN és END blokkokkal is rendelkezik, amelyek a feldolgozás előtt, illetve után futnak le, lehetővé téve az inicializálást és az összegzést.

find és xargs: Fájlok keresése és parancsok futtatása

A find parancs fájlokat és könyvtárakat keres a fájlrendszerben a megadott kritériumok alapján. A xargs pedig egy segédprogram, amely a standard bemenetéről olvas listát, és minden elemen futtat egy parancsot.

#!/bin/bash

# Összes .log fájl törlése az aktuális könyvtárból és alkönyvtáraiból
# find . -name "*.log" -delete # Biztonságosabb, ha a find támogatja a -delete-et

# Alternatíva xargs-szal (biztonságosabb, ha sok fájl van)
find . -name "*.log" -print0 | xargs -0 rm

# Keresés és jogosultságok módosítása
find . -type f -name "*.sh" -exec chmod +x {} \;

# Fájlok keresése méret alapján és listázása
find . -type f -size +10M -ls

A -print0 és xargs -0 kombinációja fontos, mert ez kezeli a fájlnevekben lévő szóközöket és speciális karaktereket, null karakterrel elválasztva az elemeket.

sort, uniq, cut, head, tail, wc

  • sort: Sorok rendezése.
  • uniq: Ismétlődő sorok eltávolítása (csak egymás melletti duplikátumokat távolít el, ezért gyakran sort után használják).
  • cut: Oszlopok kivágása szöveges fájlokból.
  • head: Fájl elejének kiírása.
  • tail: Fájl végének kiírása (-f opcióval valós idejű figyelés).
  • wc: Sorok, szavak, karakterek számlálása.
#!/bin/bash

# IP címek rendezése és egyedi listázása egy logfájlból
cat access.log | awk '{print $1}' | sort | uniq -c | sort -nr | head -n 10
# Ez a parancs kiírja a top 10 leggyakoribb IP címet az access.log-ból.

Ezeknek a parancsoknak a kombinálása pipe-ok és átirányítások segítségével adja a shell scriptek rendkívüli erejét az adatok hatékony feldolgozásában és manipulálásában.

Shell scriptek a gyakorlatban: Példák és felhasználási területek

A Shell scriptek automatizálják a rendszerfeladatokat és adminisztrációt.
A shell scriptek automatizálják a rendszerfeladatokat, időt takarítanak meg, és egyszerűsítik az ismétlődő műveleteket.

A shell scriptek alkalmazási területe rendkívül széles. Alább néhány valós példa és felhasználási terület, amelyek bemutatják a parancsfájlok sokoldalúságát.

Rendszeradminisztráció és karbantartás

1. Rendszerinformációk gyűjtése

Egy script, ami alapvető rendszerinformációkat gyűjt és kiír:

#!/bin/bash
# system_info.sh

echo "--- Rendszerinformációk: $(date) ---"
echo "Hostnév: $(hostname)"
echo "Operációs rendszer: $(uname -a)"
echo "Futtató felhasználó: $(whoami)"
echo "Aktuális könyvtár: $(pwd)"
echo ""

echo "--- Lemezhasználat ---"
df -h /

echo ""
echo "--- Memóriahasználat ---"
free -h

echo ""
echo "--- Top 5 CPU-t használó folyamat ---"
ps aux --sort=-%cpu | head -n 6

Ez a script gyors áttekintést nyújt a rendszer állapotáról, és könnyen bővíthető további ellenőrzésekkel.

2. Biztonsági mentés automatizálása

Egy egyszerű biztonsági mentés script, ami egy könyvtárat tömörít és időbélyeggel ellátva ment el:

#!/bin/bash
# backup_script.sh

SOURCE_DIR="/home/felhasznalo/dokumentumok"
BACKUP_DIR="/mnt/backup/dokumentumok_mentesek"
DATE=$(date +"%Y%m%d_%H%M%S")
BACKUP_FILE="$BACKUP_DIR/dokumentumok_backup_$DATE.tar.gz"
LOG_FILE="/var/log/backup_script.log"

mkdir -p "$BACKUP_DIR"

echo "[$(date)] Indul a biztonsági mentés a '$SOURCE_DIR' könyvtárból..." | tee -a "$LOG_FILE"

tar -czvf "$BACKUP_FILE" "$SOURCE_DIR" >> "$LOG_FILE" 2>&1

if [ $? -eq 0 ]; then
    echo "[$(date)] Sikeres mentés: '$BACKUP_FILE'" | tee -a "$LOG_FILE"
    # Régi mentések törlése (pl. 7 napnál régebbiek)
    find "$BACKUP_DIR" -type f -name "dokumentumok_backup_*.tar.gz" -mtime +7 -delete
    echo "[$(date)] Régi mentések törölve." | tee -a "$LOG_FILE"
else
    echo "[$(date)] Hiba a mentés során!" | tee -a "$LOG_FILE"
    # Hiba esetén értesítés küldése (pl. e-mailben)
    # echo "Hiba a mentés során!" | mail -s "Mentési hiba" admin@example.com
    exit 1
fi

Ez a script futtatható cron jobként, így automatikusan elvégzi a mentéseket.

Fejlesztői munkafolyamatok

3. Projekt buildelése és tesztelése

Egy script, ami egy szoftverprojektet fordít, majd futtatja a teszteket:

#!/bin/bash
# build_and_test.sh

PROJECT_DIR="/home/felhasznalo/my_project"
BUILD_LOG="$PROJECT_DIR/build.log"
TEST_LOG="$PROJECT_DIR/test.log"

cd "$PROJECT_DIR" || { echo "Hiba: Nem található a projekt könyvtár!"; exit 1; }

echo "--- Projekt fordítása ---" | tee "$BUILD_LOG"
make clean && make all >> "$BUILD_LOG" 2>&1

if [ $? -eq 0 ]; then
    echo "Fordítás sikeres." | tee -a "$BUILD_LOG"
    echo "--- Tesztek futtatása ---" | tee "$TEST_LOG"
    ./run_tests.sh >> "$TEST_LOG" 2>&1
    if [ $? -eq 0 ]; then
        echo "Tesztek sikeresen lefutottak." | tee -a "$TEST_LOG"
    else
        echo "Hiba: Tesztek sikertelenek!" | tee -a "$TEST_LOG"
        exit 1
    fi
else
    echo "Hiba: Fordítás sikertelen!" | tee -a "$BUILD_LOG"
    exit 1
fi

echo "Build és teszt folyamat befejeződött."

Ez a script integrálható Continuous Integration (CI) rendszerekbe.

Adatfeldolgozás és elemzés

4. Naplófájl elemzés

Egy script, ami egy webkiszolgáló hozzáférési naplójából kinyeri a legtöbb kérést küldő IP-címeket:

#!/bin/bash
# analyze_access_log.sh

LOG_FILE="/var/log/apache2/access.log"
OUTPUT_FILE="top_ips.txt"

if [ ! -f "$LOG_FILE" ]; then
    echo "Hiba: A naplófájl '$LOG_FILE' nem található."
    exit 1
fi

echo "--- Top 10 IP-cím a '$LOG_FILE' fájlból ---"
awk '{print $1}' "$LOG_FILE" | sort | uniq -c | sort -nr | head -n 10 > "$OUTPUT_FILE"

echo "Az eredmények elmentve ide: '$OUTPUT_FILE'"
cat "$OUTPUT_FILE"

Ez egy tipikus példa a pipe-ok és az alapvető Linux segédprogramok erejére az adatfeldolgozásban.

5. Fájlok átnevezése

Egy script, ami fájlokat nevez át egy adott minta alapján, például hozzáad egy előtagot:

#!/bin/bash
# rename_files.sh

PREFIX="uj_elotag_"
DIR="." # Az aktuális könyvtár

if [ "$#" -eq 1 ]; then
    DIR="$1"
fi

if [ ! -d "$DIR" ]; then
    echo "Hiba: A könyvtár '$DIR' nem létezik."
    exit 1
fi

echo "Fájlok átnevezése a(z) '$DIR' könyvtárban a '$PREFIX' előtaggal..."
for file in "$DIR"/*; do
    if [ -f "$file" ]; then # Csak reguláris fájlokat dolgozunk fel
        filename=$(basename "$file")
        dirname=$(dirname "$file")
        new_filename="${dirname}/${PREFIX}${filename}"
        mv "$file" "$new_filename"
        echo "Átnevezve: '$filename' -> '${PREFIX}${filename}'"
    fi
done
echo "Átnevezés befejezve."

Ezek a példák csak ízelítőt adnak a shell scriptek hatalmas potenciáljából. A képzelet és a rendelkezésre álló parancsok ismerete szabja meg a határokat, hogy milyen feladatokat automatizálhatunk velük.

Biztonsági megfontolások és legjobb gyakorlatok

A shell scriptek rendkívül erősek, de ez az erő felelősséggel jár. A rosszul megírt vagy nem kellően átgondolt scriptek biztonsági réseket okozhatnak, adatvesztést eredményezhetnek, vagy instabil rendszereket hozhatnak létre. Fontos, hogy tisztában legyünk a biztonsági kockázatokkal és a legjobb gyakorlatokkal.

Biztonsági megfontolások

1. Felhasználói bemenet ellenőrzése

Soha ne bízzunk a felhasználói bemenetben! A felhasználó által megadott adatok (parancssori argumentumok, read-del beolvasott értékek) potenciálisan rosszindulatú kódokat tartalmazhatnak (pl. parancsinjekció). Mindig ellenőrizzük és szűrjük a bemenetet, mielőtt felhasználnánk azt parancsokban.

#!/bin/bash

# ROSSZ PÉLDA (parancsinjekcióra hajlamos)
# echo "Add meg a fájlnevet:"
# read FILENAME
# rm $FILENAME # Ha a felhasználó beírja "alma.txt; rm -rf /", az katasztrófa

# JÓ PÉLDA (ellenőrzés)
echo "Add meg a fájlnevet:"
read FILENAME

# Ellenőrizzük, hogy csak alfanumerikus karaktereket, pontot és kötőjelet tartalmaz-e
if [[ ! "$FILENAME" =~ ^[a-zA-Z0-9._-]+$ ]]; then
    echo "Hiba: Érvénytelen fájlnév karakterek."
    exit 1
fi

# Ellenőrizzük, hogy a fájl létezik-e és az aktuális könyvtárban van-e
if [[ ! -f "./$FILENAME" ]]; then
    echo "Hiba: A fájl nem létezik vagy nem elérhető."
    exit 1
fi

rm "./$FILENAME" # Most már biztonságosabb

Kerüljük az eval parancs használatát, hacsak nem vagyunk 100%-ig biztosak a forrásban, mivel ez futtathat tetszőleges kódot.

2. Jogosultságok

Futtassuk a scripteket a legkevesebb jogosultsággal, amennyi a feladat elvégzéséhez szükséges. Ha egy scriptnek root jogosultságokra van szüksége, használjuk a sudo-t, és győződjünk meg róla, hogy csak a feltétlenül szükséges parancsokat futtatja rootként.

#!/bin/bash

# Néhány parancs, ami nem igényel root jogot
echo "Helyi könyvtár tartalma:"
ls -l

# Egy parancs, ami root jogot igényel
if [ "$(id -u)" -ne 0 ]; then
    echo "Ez a rész root jogosultságot igényel. Kérjük, futtassa sudo-val."
    exit 1
fi
echo "Rendszerfrissítés indítása (root):"
apt update

3. Fájlútvonalak és szóközök

Mindig használjunk idézőjeleket ("...") a változók körül, amelyek fájlútvonalakat vagy szóközt tartalmazó stringeket tárolhatnak. Ez megakadályozza a szótagolási (word splitting) problémákat és a glob (pathname expansion) értelmezést.

#!/bin/bash

MY_FILE="Ez egy fájl név szóközzel.txt"
# ROSSZ: rm $MY_FILE # A shell három külön argumentumként látná: "Ez", "egy", "fájl..."
# JÓ: rm "$MY_FILE"

# ROSSZ: for f in *.txt; do echo $f; done # Ha van "fájl név.txt", akkor hibásan kezelheti
# JÓ: for f in *.txt; do echo "$f"; done

Legjobb gyakorlatok

1. Shebang használata

Mindig kezdjük a scriptet egy shebang sorral (pl. #!/bin/bash), hogy biztosítsuk a megfelelő shell használatát.

2. Kommentek

Dokumentáljuk a kódot kommentekkel (#), magyarázva a komplex logikát, a változók célját és a script általános működését.

3. Hibakezelés és kilépési státuszok

Használjuk a set -e és set -o pipefail opciókat a script elején. Ellenőrizzük a parancsok kilépési státuszát a $? segítségével, és lépjünk ki megfelelő hibakóddal (exit 1) hiba esetén.

4. Változók és függvények

  • Használjuk a local kulcsszót a függvényen belüli változók deklarálásakor.
  • Használjunk értelmes változó- és függvényleveket.
  • Kerüljük a globális változók túlzott használatát.

5. Szabványos kimeneti és hibaüzenetek

A felhasználóval való kommunikációhoz használjuk a standard kimenetet (stdout) és a hibaüzenetekhez a standard hiba kimenetet (stderr). Ez lehetővé teszi a kimenetek átirányítását és a hibák elkülönítését.

#!/bin/bash

echo "Ez egy normál üzenet." >&1
echo "Ez egy hibaüzenet." >&2

6. Idiglenes fájlok kezelése

Ha ideiglenes fájlokat használunk, mindig gondoskodjunk a törlésükről, még hiba esetén is. A trap EXIT vagy trap ERR parancsok ideálisak erre a célra.

#!/bin/bash
TEMP_FILE=$(mktemp) # Biztonságos ideiglenes fájl létrehozása
trap "rm -f $TEMP_FILE" EXIT # Törlés kilépéskor

echo "Valami ideiglenes tartalom" > "$TEMP_FILE"
cat "$TEMP_FILE"
# ... script további része ...

7. Idézési konvenciók

Mindig idézőjelezzük a változókat, különösen, ha azok felhasználói bemenetből származnak, vagy szóközt tartalmazhatnak. Ez megakadályozza a shell szótagolási és globálási problémáit.

8. Tesztelés

Alaposan teszteljük a scripteket különböző bemenetekkel és körülmények között, beleértve a hibás eseteket is.

A biztonság és a legjobb gyakorlatok betartása nem csak a scriptek megbízhatóságát növeli, hanem hozzájárul a rendszer általános stabilitásához és biztonságához is. Egy jól megírt shell script értékes eszköz, egy rosszul megírt viszont komoly kockázatot jelenthet.

Különböző shell típusok és kompatibilitás

Bár a Bash (Bourne Again SHell) a legelterjedtebb shell a Linux és macOS rendszereken, fontos tudni, hogy számos más shell is létezik, és mindegyiknek megvannak a maga sajátosságai és előnyei. A script kompatibilitása attól függ, hogy milyen shell-specifikus funkciókat használunk, és melyik shebang sort adjuk meg.

A leggyakoribb shell típusok

  • sh (Bourne Shell): Az eredeti Unix shell, a legkevésbé funkciókban gazdag, de a legkompatibilisebb. Számos rendszeren a /bin/sh egy szimbolikus link a Bash-re (vagy Debian/Ubuntu esetén a Dash-re).
  • Bash (Bourne Again SHell): A legnépszerűbb és alapértelmezett shell a legtöbb Linux disztribúcióban és macOS-ben (régebbi verziókban). Számos kiegészítő funkcióval rendelkezik az sh-hoz képest (pl. C-stílusú for ciklus, [[ ]] feltételek, parancskiegészítés).
  • Zsh (Z Shell): Egy modern, rendkívül funkciókban gazdag shell, amely számos Bash funkciót tartalmaz, és ezen felül további fejlesztésekkel rendelkezik (pl. jobb parancskiegészítés, globális aliasok, téma-támogatás). Népszerű a fejlesztők körében.
  • Ksh (Korn Shell): Egy másik népszerű shell, amely számos funkciót vezetett be, amelyeket később a Bash is átvett. Jó teljesítmény és POSIX kompatibilitás jellemzi.
  • Fish (Friendly Interactive SHell): Egy felhasználóbarát shell, amely a könnyű használhatóságra és a "out-of-the-box" funkciókra összpontosít, mint például a szintaxis kiemelés és az automatikus javaslatok. Nem POSIX-kompatibilis, így a scriptek általában nem átvihetők más shellekbe.
  • Dash (Debian Almquist Shell): Egy minimális, gyors és POSIX-kompatibilis shell, amelyet gyakran használnak a Debian/Ubuntu rendszereken a /bin/sh szimbolikus link céljaként, a rendszerindítási scriptek felgyorsítása érdekében.

Kompatibilitás és a shebang szerepe

Amikor shell scriptet írunk, a shebang sor (pl. #!/bin/bash) az elsődleges módja annak, hogy jelezzük, melyik értelmezővel kell futtatni a scriptet. Ez kritikus a kompatibilitás szempontjából:

  • Ha egy script Bash-specifikus funkciókat használ (pl. asszociatív tömbök, (( )) aritmetikai kifejezések, [[ ]] feltételes kifejezések), akkor a shebang-nek #!/bin/bash-nak kell lennie. Ha #!/bin/sh-t használunk, és a /bin/sh egy POSIX-kompatibilis, de nem Bash shellre (pl. Dash) mutat, a script hibát fog dobni.
  • Ha a scriptet úgy írjuk, hogy csak a POSIX szabványos funkciókat használja (azaz kompatibilis az sh-val), akkor a #!/bin/sh shebang biztosítja a legszélesebb kompatibilitást. Ez jó gyakorlat lehet, ha a scriptnek sokféle Unix-szerű rendszeren kell futnia.
  • Ha Zsh-specifikus funkciókat használunk (pl. tömbök indexelése 1-től, globális aliasok), akkor a #!/bin/zsh shebang szükséges.

Kompatibilitási tippek:

  • Legyen tudatos a shell választásban: Mielőtt elkezdenénk írni, döntsük el, melyik shellre optimalizáljuk a scriptet. Ha széles kompatibilitásra van szükség, maradjunk a POSIX sh funkcióknál. Ha Bash-specifikus funkciók kényelmesebbek, használjuk a Bash-t, de ezt jelezzük a shebang-ben.
  • Kerüljük a nem szabványos funkciókat: Ha nem feltétlenül szükséges, kerüljük a shell-specifikus bővítményeket. Például, a [ ] feltételvizsgálat általában hordozhatóbb, mint a [[ ]].
  • Teszteljünk különböző környezetekben: Ha a scriptnek különböző rendszereken kell futnia, teszteljük azokat.
#!/bin/sh
# Ez a script POSIX sh kompatibilis

nev="Világ"
echo "Hello, $nev!"

if test -f "/tmp/testfile"; then
    echo "A tesztfájl létezik."
fi

# Ez a Bash-specifikus kód hibát okozna sh-ban:
# if [[ -v BASH_VERSION ]]; then
#     echo "Bash-ben futok."
# fi

A shell típusok és a kompatibilitás megértése alapvető fontosságú, különösen, ha olyan scripteket írunk, amelyeknek különböző rendszereken vagy megosztott környezetekben kell megbízhatóan működniük. A shebang megfelelő beállítása és a használt funkciók tudatos megválasztása biztosítja, hogy a scriptünk a várt módon fusson.

Share This Article
Leave a comment

Vélemény, hozzászólás?

Az e-mail címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük