Bash skripte 2 — promenljive i argumenti

U prvom delu napravili smo skriptu koja svaki put radi isto. Da bi radila sa različitim ulazima — različitim fajlom, direktorijumom ili imenom servisa — trebaju ti promenljive.

Dodela vrednosti

ime="Alen"
broj=42
putanja="/var/log/httpd"

Znak $ ispred imena vraća vrednost:

#!/usr/bin/env bash

ime="Alen"
echo "Zdravo, $ime"
Zdravo, Alen

Bez razmaka oko znaka jednakosti

Ovo je greška koju svi naprave bar jednom:

ime = "Alen"
-bash: ime: command not found

Sa razmakom bash misli da je ime komanda, a = i "Alen" njeni argumenti. Piši ime="Alen", bez razmaka ni sa jedne strane.

Imena promenljivih

Slova, brojevi i donja crta; ne smeju počinjati brojem. Bash razlikuje mala i velika slova — ime i IME su dve različite promenljive.

Uobičajena praksa: mala slova za svoje promenljive, velika za konstante na vrhu skripte i za promenljive okruženja.

LOG_DIR="/var/log/httpd"
MAX_DANA=30

danasnji_log="$LOG_DIR/error_log"

Vitičaste zagrade

Kad se odmah do imena promenljive nalazi tekst, bash ne zna gde ime prestaje:

fajl="backup"
echo "$fajl_2026.tar.gz"
.tar.gz

Bash je tražio promenljivu fajl_2026, koja ne postoji. Zagrade rešavaju granicu:

echo "${fajl}_2026.tar.gz"
backup_2026.tar.gz

Neki uvek pišu ${ime} radi doslednosti. Nije obavezno, ali ne škodi.

Navodnici

Ovo je mesto gde bash najviše iznenađuje početnike, pa vredi pažljivo.

Dvostruki navodnici — promenljive se zamenjuju

ime="Alen"
echo "Zdravo, $ime"
Zdravo, Alen

Jednostruki navodnici — sve doslovno

echo 'Zdravo, $ime'
Zdravo, $ime

Bez navodnika — opasno

Bash rastavlja vrednost po razmacima i tumači specijalne znake:

fajl="moj dokument.txt"

rm $fajl      # pokušava da obriše "moj" i "dokument.txt"
rm "$fajl"    # briše "moj dokument.txt"

Pravilo koje ti štedi sate traženja greške: promenljive uvek piši u dvostrukim navodnicima, osim kad tačno znaš zašto ne bi.

Ovo nije stilska preporuka. Skripta koja radi na tvom test fajlu backup.txt lako pukne na produkcijskom backup stari.txt — a sa rm to nije bezopasan kvar.

Rezultat komande u promenljivoj

Zapis $( ) izvršava komandu i vraća njen izlaz:

datum=$(date +%Y-%m-%d)
korisnik=$(whoami)
broj_fajlova=$(ls -1 | wc -l)

echo "Danas je $datum, prijavljen si kao $korisnik"
echo "U ovom direktorijumu ima $broj_fajlova stavki"

Ovo je osnovni alat za pravljenje imena fajlova sa datumom:

ime_backupa="baza_$(date +%Y%m%d_%H%M).sql"
echo "$ime_backupa"
baza_20260821_1435.sql

Videćeš i stariji zapis sa obrnutim apostrofima — `date`. Radi isto, ali se ne može ugnežđivati i teško se razlikuje od običnog apostrofa. Koristi $( ).

Argumenti komandne linije

Ovo je ono što skriptu čini upotrebljivom. Vrednosti koje joj proslediš pri pokretanju dostupne su preko numerisanih promenljivih:

#!/usr/bin/env bash

echo "Ime skripte: $0"
echo "Prvi argument: $1"
echo "Drugi argument: $2"
echo "Ukupno argumenata: $#"
echo "Svi argumenti: $@"
$ ./test.sh alfa beta
Ime skripte: ./test.sh
Prvi argument: alfa
Drugi argument: beta
Ukupno argumenata: 2
Svi argumenti: alfa beta
ZapisZnačenje
$0ime skripte
$1$9prvi do deveti argument
${10}deseti i dalje — obavezne zagrade
$#broj argumenata
$@svi argumenti, svaki kao zasebna stavka
$?izlazni kod prethodne komande
$$PID same skripte

Praktičan primer

#!/usr/bin/env bash
# Pregled poslednjih grešaka servisa
# Upotreba: ./greske.sh ime-servisa

servis="$1"

echo "Poslednjih 20 zapisa za servis: $servis"
journalctl -u "$servis" -n 20 --no-pager
$ ./greske.sh httpd
$ ./greske.sh sshd

Jedna skripta, bilo koji servis. Više o journalctl-u u posebnoj lekciji.

Provera da je argument prosleđen

Ako korisnik ne prosledi ništa, $1 je prazno i skripta radi nešto neočekivano. Zaustavi je odmah:

#!/usr/bin/env bash

if [ -z "$1" ]; then
    echo "Upotreba: $0 ime-servisa"
    exit 1
fi

servis="$1"
journalctl -u "$servis" -n 20 --no-pager

Oznaka -z proverava da li je vrednost prazna. Detaljno o uslovima u sledećem delu — ovaj obrazac zapamti kao gotov, jer ide na početak skoro svake skripte koja prima argumente.

$@ i $* nisu isto

"$@"    svaki argument ostaje zasebna stavka
"$*"    svi argumenti spojeni u jedan string

Skoro uvek ti treba "$@", sa navodnicima. Jedino tako argumenti koji sadrže razmake ostaju celi.

Podrazumevane vrednosti

Ako argument nije prosleđen, uzmi zadatu vrednost:

broj_redova="${1:-20}"
direktorijum="${2:-/var/log}"

echo "Prikazujem $broj_redova redova iz $direktorijum"
$ ./skripta.sh
Prikazujem 20 redova iz /var/log

$ ./skripta.sh 50 /var/log/httpd
Prikazujem 50 redova iz /var/log/httpd

Srodni oblik prekida rad sa porukom ako promenljiva nije postavljena:

servis="${1:?Moraš navesti ime servisa}"

Unos od korisnika

Komanda read čeka da korisnik nešto otkuca:

#!/usr/bin/env bash

read -p "Kako se zoveš? " ime
echo "Zdravo, $ime"

Bez ispisivanja na ekran, za lozinke:

read -sp "Lozinka: " lozinka
echo

Sa vremenskim ograničenjem:

read -t 10 -p "Nastavi? (d/n) " odgovor

Napomena: read je koristan dok skriptu koristiš ručno, ali skripta koju pokreće cron nema kome da postavi pitanje — tu se zaglavi i visi. Za automatizovane poslove sve prosleđuj kao argumente.

Aritmetika

Bash podrazumevano radi sa tekstom. Za računanje koristi $(( )):

a=10
b=3

echo $((a + b))     # 13
echo $((a - b))     # 7
echo $((a * b))     # 30
echo $((a / b))     # 3   -- celobrojno deljenje!
echo $((a % b))     # 1   -- ostatak

Unutar zagrada $ ispred imena nije obavezan.

Uvećavanje brojača:

brojac=0
brojac=$((brojac + 1))

Bash ne zna za decimalne brojeve. Ako ti trebaju, koristi bc:

echo "scale=2; 10 / 3" | bc
3.33

Promenljive okruženja

Neke promenljive postoje pre nego što ih ti postaviš:

echo "$HOME"      # /home/alen
echo "$USER"      # alen
echo "$PWD"       # trenutni direktorijum
echo "$PATH"
echo "$HOSTNAME"

Ceo spisak daje env. Ove promenljive slobodno koristi u skriptama, ali izbegavaj da im dodeljuješ svoje vrednosti — naročito PATH i HOME.

export

Promenljiva je podrazumevano vidljiva samo u skripti u kojoj je napravljena. Da bi je videli i programi koje ta skripta pokreće:

export APP_MODE="production"
./druga-skripta.sh

Obrada teksta u promenljivoj

Bash ume dosta i bez pozivanja spoljnih alata:

fajl="/var/log/httpd/error_log.gz"

echo "${#fajl}"           # dužina: 29
echo "${fajl##*/}"        # samo ime fajla: error_log.gz
echo "${fajl%/*}"         # samo putanja: /var/log/httpd
echo "${fajl%.gz}"        # bez nastavka: /var/log/httpd/error_log
echo "${fajl/log/LOG}"    # zamena prvog pojavljivanja
echo "${fajl//log/LOG}"   # zamena svih pojavljivanja

Zapisi nisu lepi za pamćenje, ali su brzi i ne pokreću novi proces — što je bitno u petljama sa hiljadama ponavljanja. Za složenije stvari tu su sed i awk.

Primer: skripta za backup direktorijuma

#!/usr/bin/env bash
# Arhivira zadati direktorijum sa datumom u imenu
# Upotreba: ./backup.sh /putanja/do/direktorijuma [odrediste]

izvor="$1"
odrediste="${2:-/backup}"

if [ -z "$izvor" ]; then
    echo "Upotreba: $0 /putanja/do/direktorijuma [odrediste]"
    exit 1
fi

datum=$(date +%Y%m%d_%H%M)
naziv=$(basename "$izvor")
arhiva="$odrediste/${naziv}_${datum}.tar.gz"

echo "Arhiviram $izvor u $arhiva"

tar -czf "$arhiva" "$izvor"

echo "Gotovo. Veličina: $(du -h "$arhiva" | cut -f1)"
$ ./backup.sh /etc/httpd
Arhiviram /etc/httpd u /backup/httpd_20260821_1435.tar.gz
Gotovo. Veličina: 84K

Skripta još ne proverava da li izvor postoji, da li je tar uspeo, niti briše stare arhive. Sve to dodajemo u naredna dva dela.

Vežba

Napiši skriptu koja prima ime korisnika kao argument i ispisuje:

  • njegov UID i grupe (id)
  • njegov home direktorijum
  • koliko taj home zauzima (du -sh)
  • kada se poslednji put prijavio (lastlog -u)

Ako argument nije prosleđen, neka koristi trenutno prijavljenog korisnika kao podrazumevanu vrednost.


Sledeći deo: uslovi i petlje — kako da skripta donosi odluke i ponavlja posao nad više fajlova.

Povezano: Bash skripte 1 — prva skripta · Piping i redirekcija · Programiranje

Comments

Popular posts from this blog

Konverzija tipova podataka u Pythonu

Početak u Linuxu — šta je i zašto se uči

groupadd