Gym
lesson

Funkcije

U ovoj lekciji naucicemo kako da organizujemo Bash skripte pomocu funkcija — jednog od najvaznijiih alata za pisanje citljivog i odrzivog koda.

Sta je funkcija?

Funkcija je minijaturna skripta unutar skripte. Jednom je definisete, a zatim je pozivate koliko god puta zelite. Dva glavna razloga za koriscenje:

  • Izbegavanje ponavljanja — isti kod ne pisete vise puta
  • Organizacija — skripta postaje pregledna, svaki zadatak ima svoje ime

Definisanje funkcije

Postoje dve sintakse:

# Preporučena forma:
ime_funkcije() {
    echo "Hello iz funkcije"
}

# Alternativna (sa kljucnom recju function):
function ime_funkcije {
    echo "Hello"
}

Obe forme su ispravne. Prva je kompaktnija i cesca u praksi.

Vazno: Funkcija mora biti definisana pre nego sto je pozovete. Bash cita skriptu odozgo nadole — ako pozovete funkciju pre njene definicije, dobicete gresku command not found.

Pozivanje funkcije

Funkciju pozivate tako sto napisete njeno ime — bez zagrada:

#!/bin/bash

pozdravi() {
    echo "Zdravo iz funkcije!"
}

pozdravi    # Poziv — nema zagrada
pozdravi    # Mozete pozivati vise puta

Izlaz:

Zdravo iz funkcije!
Zdravo iz funkcije!

Paznja: Za razliku od vecine programskih jezika, u Bash-u se funkcija ne poziva sa zagradama. pozdravi() znaci definisanje, a pozdravi znaci pozivanje.

Argumenti funkcije

Funkcije primaju argumente na isti nacin kao i skripte — kroz $1, $2, itd.:

#!/bin/bash

pozdravi() {
    echo "Zdravo, $1!"
}

pozdravi Marko       # Zdravo, Marko!
pozdravi Ana         # Zdravo, Ana!
pozdravi "Jovana P"  # Zdravo, Jovana P!

Sve specijalne varijable rade unutar funkcije:

Varijabla Znacenje unutar funkcije
$1, $2, ... Argumenti prosledjeni funkciji
$# Broj argumenata
$@ Svi argumenti kao zasebne reci

Primer sa vise argumenata i proverom:

#!/bin/bash

kopiraj_fajl() {
    if [[ $# -ne 2 ]]; then
        echo "Koriscenje: kopiraj_fajl <izvor> <odrediste>"
        return 1
    fi

    cp "$1" "$2"
    echo "Kopiran: $1 -> $2"
}

kopiraj_fajl dokument.txt /tmp/dokument.txt
kopiraj_fajl slika.png    # Nedostaje argument — ispisuje uputstvo

Povratne vrednosti

Funkcije u Bash-u ne vracaju vrednosti kao u programiranju. Postoje dva nacina da prenesete rezultat:

Nacin 1: Echo + komandna supstitucija

Funkcija ispisuje rezultat, a pozivalac ga hvata pomocu $(...):

#!/bin/bash

saberi() {
    echo $(($1 + $2))
}

zbir=$(saberi 3 5)
echo "3 + 5 = $zbir"   # 3 + 5 = 8

rezultat=$(saberi 10 7)
echo "10 + 7 = $rezultat"   # 10 + 7 = 17

Nacin 2: Exit kod sa return

return vraca broj od 0 do 255 — samo brojeve, ne stringove:

  • return 0 — uspeh
  • return 1 (ili bilo koji drugi broj) — greska
#!/bin/bash

proveri_broj() {
    if [[ $1 -gt 0 ]]; then
        return 0    # Uspeh — broj je pozitivan
    else
        return 1    # Greska — broj nije pozitivan
    fi
}

proveri_broj 5
if [[ $? -eq 0 ]]; then
    echo "Broj je pozitivan"
else
    echo "Broj nije pozitivan"
fi

# Kompaktnija forma:
proveri_broj -3 || echo "Broj nije pozitivan"

Cesta greska: return "greska" — ovo ne radi. return prima samo cele brojeve 0-255. Za vracanje teksta koristite echo + komandnu supstituciju.

Lokalne varijable

Po defaultu, sve varijable u funkciji su globalne — menjaju vrednosti van funkcije. Ovo moze biti opasno:

#!/bin/bash

ime="Marko"

promena() {
    ime="Ana"    # Menja globalnu varijablu!
}

echo "$ime"     # Marko
promena
echo "$ime"     # Ana — neocekivano!

Resenje je kljucna rec local:

#!/bin/bash

ime="Marko"

promena() {
    local ime="Ana"    # Lokalna varijabla — ne dira globalnu
    echo "Unutra: $ime"
}

echo "Pre: $ime"     # Marko
promena              # Unutra: Ana
echo "Posle: $ime"   # Marko — globalna ostaje nepromenjena

Pravilo: Uvek koristite local za varijable unutar funkcija, osim ako namerno zelite da promenite globalnu vrednost.

Prakticna skripta

Uzmimo sve zajedno u realnijoj skripti:

#!/bin/bash
# backup.sh — skripta sa funkcijama

proveri_dir() {
    if [[ ! -d "$1" ]]; then
        echo "Greska: '$1' ne postoji ili nije direktorijum"
        return 1
    fi
    return 0
}

napravi_backup() {
    local izvor="$1"
    local odrediste="$2"
    local ime_backup="backup_$(date +%Y%m%d_%H%M%S)"

    cp -r "$izvor" "$odrediste/$ime_backup"
    echo "Backup napravljen: $odrediste/$ime_backup"
}

ispisi_velicinu() {
    local dir="$1"
    local velicina=$(du -sh "$dir" 2>/dev/null | cut -f1)
    echo "Velicina '$dir': $velicina"
}

# Glavni deo skripte — funkcije vec definisane gore
IZVOR="/home/student/dokumenti"
ODREDISTE="/tmp"

proveri_dir "$IZVOR" || exit 1
proveri_dir "$ODREDISTE" || exit 1

napravi_backup "$IZVOR" "$ODREDISTE"
ispisi_velicinu "$IZVOR"

Sta cini ovu skriptu dobrom:

  • Svaki zadatak ima ime (proveri_dir, napravi_backup)
  • Koristimo local za sve unutrasnje varijable
  • Proveravamo greske sa return 1 i || exit 1
  • Glavni deo skripte je kratak i citljiv

Ceste greske

Poziv pre definicije

#!/bin/bash

pozdravi    # GRESKA: command not found

pozdravi() {
    echo "Zdravo!"
}

Resenje: definicije funkcija staviti na vrh skripte, pozive na dno.

return sa stringom

proveri() {
    return "greska"    # GRESKA: ocekuje broj 0-255
}

Resenje: za vracanje teksta koristiti echo, za status koristiti return 0 / return 1.

Zaboravljeno local

#!/bin/bash
BROJAC=100

uvecaj() {
    BROJAC=$((BROJAC + 1))    # Menja globalnu!
}

uvecaj
echo $BROJAC    # 101 — ali da li smo to zeleli?

Resenje: koristiti local BROJAC unutar funkcije ako je promenljiva lokalna po prirodi.

Rezime

Koncept Sintaksa Napomena
Definisanje ime() { ... } Pre poziva!
Pozivanje ime arg1 arg2 Bez zagrada
Argumenti $1, $2, $#, $@ Kao u skripti
Povratna vrednost (tekst) echo rezultat + $(ime) Najcesci nacin
Povratna vrednost (status) return 0 / return 1 Samo 0-255
Lokalna varijabla local ime=vrednost Uvek koristiti

U sledecim vezbama primenjujemo sve koncepte iz lekcija 01-05 — varijable, uslove, petlje i funkcije — u realnim skriptama.