Džokeri i navodnici — kako shell proširuje šablone

Kad kucaš ls *.txt, komanda ls nikada ne vidi zvezdicu. Shell je razreši pre nego što pokrene komandu i prosledi joj gotov spisak imena fajlova. To je jedna rečenica koja objašnjava skoro sve čudne situacije sa džokerima — i kad rade, i kad ne rade.

Ova lekcija pokriva džokere (*, ?, [ ]) i tri načina da shell-u kažeš da ne dira ono što si napisao (navodnici i kosa crta).

Ko zapravo radi posao

Pretpostavimo ovaj direktorijum:

$ ls
beleske.txt        izvestaj-2025.pdf  slika10.png  skripta.sh
izvestaj-2024.pdf  slika1.png         slika2.png

Kad kucaš ls *.png, dešava se ovo:

  1. Shell pogleda direktorijum i pronađe imena koja odgovaraju šablonu.
  2. Shell zameni *.png tim imenima, sortiranim po abecedi.
  3. Tek onda pokreće ls slika1.png slika10.png slika2.png.

Najlakši način da to vidiš svojim očima je komanda echo — ona samo ispiše ono što joj shell prosledi:

$ echo *.png
slika1.png slika10.png slika2.png

Zapamti ovo pravilo: pre svake opasne komande sa džokerom, prvo kucaj echo sa istim šablonom. Ako je ispis onaj koji očekuješ, zameni echo sa rm ili mv. Ovo je navika koja spasava podatke.

Zvezdica: bilo koji broj znakova

* se poklapa sa bilo kojim nizom znakova — uključujući i prazan niz.

$ ls *.pdf
izvestaj-2024.pdf  izvestaj-2025.pdf

$ ls izvestaj*
izvestaj-2024.pdf  izvestaj-2025.pdf

$ ls *e*
beleske.txt  izvestaj-2024.pdf  izvestaj-2025.pdf

Pošto se poklapa i sa nulom znakova, ls skripta* pronaći će i fajl koji se zove tačno skripta.

Upitnik: tačno jedan znak

? stoji za tačno jedan bilo koji znak — ni manje, ni više. Ovo je razlika koja se najlakše zapamti kroz primer:

$ ls slika?.png
slika1.png  slika2.png

$ ls slika*.png
slika1.png  slika10.png  slika2.png

slika10.png ima dva znaka između „slika" i „.png", pa ga ? preskače. Ako ti treba baš dvocifreno: ls slika??.png.

Uglaste zagrade: jedan znak iz skupa

[ ] je precizniji upitnik — poklapa jedan znak, ali samo iz liste koju ti navedeš.

$ ls izvestaj-202[45].pdf
izvestaj-2024.pdf  izvestaj-2025.pdf

$ ls slika[12].png
slika1.png  slika2.png

Unutar zagrada radi i opseg, sa crticom:

  • [0-9] — bilo koja cifra
  • [a-z] — bilo koje malo slovo
  • [a-zA-Z0-9] — slovo ili cifra

Uzvičnik (ili kapica) na početku znači negaciju — „bilo koji znak osim ovih":

$ ls slika[!1].png
slika2.png

[^1] radi isto. Obrati pažnju: negira se samo jedan znak, ne ceo ostatak imena — zato slika10.png ovde ne prolazi (ima dva znaka posle „slika").

Vitičaste zagrade: proširenje liste

{ } tehnički nije džoker, jer ne gleda šta postoji na disku — samo generiše kombinacije teksta. Zato radi i kad fajlovi tek treba da nastanu:

$ echo fajl{1,2,3}.txt
fajl1.txt fajl2.txt fajl3.txt

$ touch log-{01..05}.txt
$ ls log*
log-01.txt  log-02.txt  log-03.txt  log-04.txt  log-05.txt

Najkorisniji trik u praksi — brza rezervna kopija fajla pre nego što ga menjaš:

$ cp /etc/ssh/sshd_config{,.bak}

Shell to proširi u cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak, jer je prva stavka u listi prazna. Više o kopiranju ima na stranici cp.

Šta džokeri ne rade

Ne hvataju skrivene fajlove

Imena koja počinju tačkom zvezdica namerno preskače:

$ ls -a
.  ..  .bashrc  .profile  beleske.txt  skripta.sh

$ echo *
beleske.txt skripta.sh

Zato cp * /backup/ neće prekopirati tvoja podešavanja. Ako ti trebaju i skriveni fajlovi, koristi .[!.]* — a nikako rm -r .*, jer taj šablon zahvata i .., odnosno roditeljski direktorijum.

Ne prelaze preko kose crte

* se ne poklapa sa /. ls *.txt gleda samo tekući direktorijum. Za jedan nivo dublje treba ls */*.txt. Za rekurzivnu pretragu kroz celo stablo koristi se find, a ne džoker.

Kad nema poklapanja, shell ne dira šablon

Ovo je izvor jedne od najčešćih zbunjujućih poruka:

$ ls *.doc
ls: cannot access '*.doc': No such file or directory

Nema nijednog .doc fajla, pa shell nema šta da zameni i prosleđuje *.doc doslovno. ls onda pokušava da otvori fajl koji se bukvalno zove „zvezdica tačka doc". Poruka nije bug — ona ti govori da šablon nije pogodio ništa.

Navodnici: kako da shell ostavi tekst na miru

Postoje tri načina da se zaštiti tekst, i razlikuju se po tome koliko strogo štite.

1. Jednostruki navodnici — sve doslovno

$ echo 'Cena je $5 i pise se * ovako'
Cena je $5 i pise se * ovako

Unutar ' ' ništa nema posebno značenje. Jedino što ne može da stane unutra jeste sam apostrof.

2. Dvostruki navodnici — čuvaju razmake, ali ne i promenljive

$ echo "Danas je $(date +%d.%m.%Y)"
Danas je 22.08.2026.

$ echo "Cena je $5"
Cena je

Drugi primer iznenađuje početnike: unutar " " znak $ i dalje radi, a $5 je peti argument skripte — prazan. Ako želiš da se ispiše dolar, treba 'Cena je $5' ili "Cena je \$5".

Ukratko: dvostruki navodnici gase džokere i razmake, ali ostavljaju $, ` i \ aktivnima.

3. Obrnuta kosa crta — štiti tačno jedan znak

$ touch moj\ fajl.txt
$ echo 3 \* 4
3 * 4

Tri greške koje svi naprave bar jednom

Fajl sa razmakom u imenu

$ rm moj fajl.txt
rm: cannot remove 'moj': No such file or directory
rm: cannot remove 'fajl.txt': No such file or directory

Shell je razmak protumačio kao granicu između dva argumenta. Ispravno je rm "moj fajl.txt" ili rm moj\ fajl.txt. Isto važi i za promenljive u skriptama — uvek pod dvostrukim navodnicima:

$ fajl="moj fajl.txt"
$ ls $fajl
ls: cannot access 'moj': No such file or directory
$ ls "$fajl"
moj fajl.txt

Šablon koji treba da vidi sama komanda

$ find . -name *.txt
find: paths must precede expression: 'log-02.txt'

Shell je proširio *.txt u spisak fajlova pre nego što je find uopšte pokrenut, pa je find dobio gomilu imena tamo gde očekuje jedan obrazac. find ima sopstveni sistem šablona i traži da mu tekst stigne netaknut:

$ find . -name '*.txt'
./log-01.txt
./log-02.txt
./beleske.txt

Isto pravilo važi i za grep: obrazac ide pod navodnike, i zato što sadrži specijalne znake i zato što često ima razmake.

$ grep 'connection refused' /var/log/syslog

Razmak na pogrešnom mestu

$ rm * .txt

Namera je bila rm *.txt. Ono što se zaista izvršilo jeste rm * — brisanje svega u direktorijumu — a zatim još i pokušaj brisanja fajla imenom .txt. Ovo je tačno onaj slučaj u kome navika sa echo iz uvoda spasava dan. Detaljnije o opasnostima brisanja ima na stranici rm.

Bonus: fajl koji počinje crticom

Ako se fajl zove -izvestaj.txt, komanda ga tumači kao opciju:

$ rm -izvestaj.txt
rm: invalid option -- 'i'

Rešenje je da mu daš putanju koja ne počinje crticom, ili da odvojiš opcije od argumenata sa --:

$ rm ./-izvestaj.txt
$ rm -- -izvestaj.txt

Kratka referenca

  • * — bilo koji broj znakova, uključujući nijedan
  • ? — tačno jedan znak
  • [abc] — jedan znak iz skupa
  • [a-z], [0-9] — jedan znak iz opsega
  • [!abc] — jedan znak koji nije iz skupa
  • {a,b,c} — generiše listu, ne gleda disk
  • 'tekst' — sve doslovno
  • "tekst" — doslovno osim $, `, \
  • \z — štiti tačno jedan znak

Vežba

Napravi prazan direktorijum i u njemu ovo:

$ mkdir vezba && cd vezba
$ touch izvestaj-{2023,2024,2025}.pdf slika{1,2,10}.png beleske.txt .skriveno

Pa proveri da li možeš, koristeći echo, da napišeš šablon koji pogađa:

  1. samo PDF fajlove iz 2024. i 2025. godine
  2. samo slika1.png i slika2.png, ali ne i slika10.png
  3. sve osim PDF fajlova

Za treći zadatak ti treba nešto što nismo pominjali — pogledaj u man stranici za bash odeljak Pattern Matching i pojam extglob. Traženje odgovora u dokumentaciji je deo vežbe.


Kad ti džokeri uđu u prste, sledeći korak je da razumeš gde se ti fajlovi uopšte nalaze: Direktorijumi i fajlovi Linux sistema.

Cela lekcija je deo vodiča Linux osnove.

Comments

Popular posts from this blog

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

Konverzija tipova podataka u Pythonu

groupadd