nav_dugme codeBlog codeBlog
  • početna Početna stranica
  • Sačuvani članci Sačuvani članci
  • Članci
     (spisak)
  • Kontakt
Povratak na vrh stranice

Info & povezani članci Info o članku - dugme

Info

trejler_sat Datum objave: 19.09.2022.

trejler_olovka Poslednja izmena: 12.01.2024.

trejler_dokument Jezici: Shell
C/C++
JavaScript
Python

trejler_teg_narandzasti Težina: 7/10

linux
gnu/linux
unix
open source
slobodni softver
Shell
regularni izrazi
regex
komandna linija
datoteke
obrada teksta
teorija
saveti
zanimljivosti

Tema: GNU/Linux

1. deo - Uvod2. deo - Osnovne komande4. deo – Shell skripte i automatizacija procesa

Povezani članci

ASCII, Unicode i UTF - Predstavljanje znakova na računarimaUNIX Time - Predstavljanje datuma i vremena na računarimaIzbor prvog programskog jezikaRegularni izrazi - napredna pretraga tekstaPokretanje lokalnog web serveraUvod u PythonPostfiksna notacija - kako računari računaju?Operacije sa tekstualnim datotekama u programskim jezicima C i PythonŠablonske niske u programskim jezicimaCallback funkcije i lambda izraziOperacije sa bitovima u programskom jeziku CKako napraviti syntax highlighter
Svi članci
There are only two industries that refer to their customers as ‘users’.
Edward Tufte

GNU/Linux - 3. deo – Napredne komande

Facebook LinkedIn Twitter Viber WhatsApp E-mail
zoom_plus zoom_minus bookmark
početna > Članci > Teorija

Uvod

Temeljno poznavanje osnovnih komandi važan je preduslov za efikasno obavljanje poslova koji su vezani za razvoj softvera ili projektovanje web sajtova u nekom od UNIX-olikih okruženja, međutim, u praksi je više nego preporučljivo biti upoznat i sa izvesnim brojem naprednijih programa za obradu teksta u konzoli (bar nekoliko), * preko kojih se rezultat izvršavanja osnovnih komandi može izmeniti, filtrirati ili formatirati na prikladniji način.

Pored napredni(ji)h komandi za obradu teksta, administracija sistema takođe obuhvata (bar povremeno) korišćenje shell skripti. **

Pod naprednom obradom teksta (da pojasnimo), ovoga puta ne podrazumevamo upotrebu konzolnih editora kao što su Vim ili Emacs, već mislimo na obavljanje operacija sa tekstom u okviru komandne linije, to jest, na upotrebu programa kao što su grep, sed i awk, koji po potrebi primaju tekst sa standardnog ulaza, obavljaju obradu i šalju tekst na standardni izlaz.

* Kao i obično, preporučujemo da se ne upuštate u savladavanje novih veština ukoliko veštine sa prethodnog nivoa niste savladali na odgovarajući način.

** Alatima za naprednu obradu teksta u konzoli bavićemo se u ovom članku, a shell skripte (i još nekolicina drugih mehanizama za automatizaciju), biće tema sledećeg članka.

Još nekoliko napomena

Pošto polako počinjemo da se bavimo naprednijim UNIX komandama, želimo da što pravilnije "naštimamo" očekivanja čitalaca, i stoga ćemo se ukratko osvrnuti na određene pojave ....

Pre svega, može se reći da oblast UNIX/Linux komandi predstavlja svojevrstan "okean" (pojavu koju odlikuje: i velika širina, i velika dubina), i stoga, sam termin "napredne komande" koji smo izabrali za naslov članka (odnosno, preciznije - "iskazani nivo naprednosti"), može biti protumačen na više načina.

Sa jedne strane, u odnosu na određene komande tj. programe (koje nismo pominjali do sada a "kakvih inače ima na Linux-u"), komande koje ćemo prikazati u ovom članku ne deluju 'posebno napredno'.

Sa druge strane - same po sebi - prilično su napredne!

U članku neće biti prikazane sve opcije svih programa (ni izdaleka, pogotovo kada je u pitanju program awk), ali, bez obzira na navedeno, opcije koje ćemo prikazati, same po sebi omogućavaju prilično napredne vidove obrade teksta (uz mnoštvo zanimljivih kombinacija).

Najprostije bismo mogli reći da će u članku biti prikazan "osnovni nivo naprednijih komandi" (pri čemu je akcenat na prikazivanju ideja koje stoje iza samih alata i praktičnim primerima, a ne "na nabrajanju opcija").

Tehnike koje ćemo prikazati u nastavku, u praksi su sasvim dovoljne (uz bar ponešto samostalnog istraživanja i 'nadogradnje'), za korisnike koji ne žele previše da se udubljuju u tematiku konzolnih komandi pod Linux-om već samo žele što bolju osnovu za korišćenje drugih programa (recimo da se navedeno odnosi na dobar deo programera), ali, takođe se može reći i da je gradivo iz članka sasvim dobra osnova za čitaoce koji žele da istražuju nadalje i što više se udube u tematiku.

Doduše, kad je u pitanju takvo udubljivanje .... "budite upozoreni" 🙂 ....

Komande u terminalu (kao što smo naveli još u uvodnom članku), na početku pomalo "žuljaju" većinu korisnika koji su navikli na GUI interfejs, ali, uz iole ozbiljniju količinu uloženog truda, nije teško navići se (odnosno, nije teško prevazići 'početne neudobnosti').

Međutim (na ovom mestu dolazimo do prave poente): ukoliko neko istraje i ne izgubi interesovanje, lako i neosetno vremenom dolazi u situaciju u kojoj, ne samo da Linux komande "ne žuljaju", već, naprotiv - pobuđuju interesovanje na dubokom ličnom nivou (i stoga trošenje vremena na proučavanje detalja ne deluje više kao "kuluk", već kao zabava).

Srećom, navedene 'zanimacije' su sasvim u skladu sa akademskim obrazovanjem i profesionalnim usavršavanjem mlađih programera, i sve naučeno, najčešće veoma dobro dođe u praksi.

U budućnosti, sasvim lako se može desiti da napišemo i članak koji obuhvata mnogo više opcija i primera koji su vezani za programe grep, sed i awk, a sada je vreme da se vratimo na posao ....

Grep - pretraga teksta preko regularnih izraza

Program grep (skraćenica za "globally search for a regular expression and print matching lines"), pronalazi linije teksta koje se poklapaju sa određenim obrascem.

Tekst koji se pretražuje može biti izlaz prethodne komande (koji se "pajpuje" u grep), a mogu se takođe direktno pretraživati i tekstualne datoteke (u kom slučaju je naziv datoteke jedan od argumenata).

Komanda grep poziva se po sledećoj šemi:

		
$ grep [opcije] obrazac [datoteka]
		
	
Slika 1. - Opšta šema izvršavanja programa grep.

Sa prosleđivanjem (tj. "pajpovanjem") izlaza određene komande u program grep, već smo se upoznali u uvodnom članku ....

		
$ ls -la | grep 'Sep 26'

2.4K  Nov 26  00:44
50K   Nov 26  08:33
143   Nov 26  11:54
		
	
Slika 2. - Primer pajpovanja izlaza komande ls u program grep.

.... a ovoga puta više pažnje ćemo obratiti na primere pretrage teksta koji se učitava direktno iz datoteka.

.... naravno, uz napomenu da svi vidovi pretrage sa kojima ćemo se u nastavku upoznati, važe i onda kada se tekstualni izlaz prethodno izvršenog programa pajpuje u grep zarad dalje obrade.

Pretraga teksta iz datoteka

Datoteka koju ćemo koristiti za primere u članku, sadrži (fiktivne) podatke o osobama koje učestvuju u održavanju velike društvene mreže (po id-ovima se da naslutiti da mreža ima više stotina hiljada korisnika, ali, koristimo sažetu listu koja je dobijena filtracijom veće tabele, u kojoj su zapisani svi korisnici, uključujući i osoblje sajta).

		
# Ime    Prezime    priv  funkcija  datum_rođenja  id 
---------------------------------------------------------
1 Milan  Jovanović  30    admin     1984-10-15     162
2 Dejan  Kovačević  30    admin     1981-03-21     1770
3 Ivana  Marković   20    moderator 1986-11-01     18324
4 Petar  Komnenović 10    saradnik  1992-08-08     19427
5 Jelena Spasić     10    saradnik  1985-01-12     191981
6 Nevena Katić      10    saradnik  2000-04-05     204628
7 Oliver Petrović   10    saradnik  1993-09-04     215283
8 Stojan Milić      10    saradnik  1995-03-05     294648
		
	
Slika 3. - Sadržaj datoteke saradnici.txt, koju ćemo koristiti u primerima.

Datoteku možete preuzeti preko sledećeg linka: saradnici.txt, uz napomenu da datoteka sadrži i kolonu sa email adresama, koju smo u prikazu u članku izostavili zarad preglednosti (verujemo da primer može biti zanimljiv i za naknadno samostalno istraživanje, i stoga dodatni podaci - koji se mogu pretraživati, filtrirati i sl. - neće škoditi. :)

Za početak, pozabavićemo se jednostavnim primerom pretrage, bez regularnih izraza.

Ukoliko upotrebimo sledeću nisku (u svojstvu vrlo jednostavnog 'obrasca') ....

		
$ grep 'admin' saradnici.txt 
		
	
Slika 4. - Pretraga niske "admin" u datoteci saradnici.txt.

.... pretraga daje rezultat koji je korektan (i očekivan):

		
1 Milan  Jovanović  30    admin     1984-10-15     162
2 Dejan  Kovačević  30    admin     1981-03-21     1770
		
	
Slika 5. - Rezultat izvršavanja prethodne komande.

Međutim, ako pokušamo - po istom principu - da pronađemo osobu (ili osobe), pri čemu se kao kriterijum naizgled koristi 'godina rođenja' ....

		
$ grep '1981' saradnici.txt 
		
	
Slika 6. - Primer pretrage koja neće vratiti očekivani rezultat.

.... rezultat neće biti u skladu sa očekivanjima (jer "moglo bi se reći" da samo tražimo običnu nisku koja se može protumačiti na više načina):

		
2 Dejan  Kovačević  30    admin     1981-03-21     1770
5 Jelena Spasić     10    saradnik  1985-01-12     191981
		
	
Slika 7. - Rezultat izvršavanja prethodne komande.

U jednom redu, uneta niska (zaista) predstavlja godinu rođenja, dok u drugom redu niska predstavlja (samo) deo id-a saradnika.

Bez odgovarajućih mehanizama za prepoznavanje obrazaca, jasno je da rezultati obične pretrage mogu biti diskutabilni i inače (pogotovo u većim kolekcijama tekstualnih podataka), i upravo to smo hteli da potcrtamo preko jednostavnog primera.

U konkretnom slučaju koji razmatramo, problem se može rešiti na trivijalan način, budući da su podaci u datumima rođenja saradnika razdvojeni crticama (i stoga bi npr. pretraga niske "1981-" sasvim urodila plodom).

Međutim, zarad opšteg obrazovanja (to jest, zbog toga što u mnogim drugim situacijama nije toliko jednostavno pronaći "priručno rešenje"), "pravićemo se" da ne vidimo jednostavni obrazac i sprovešćemo pretragu preko regularnog izraza.

U slučaju da se u drugim kolonama ne pojavljuju datumi (niti drugi podaci koji po svom formatu 'liče' na datume), regularni izraz, odnosno, cela komanda pretrage - koja prepoznaje datume koji pripadaju ranije navedenoj godini - može se definisati na sledeći način:

		
grep -E '\b1981-[[:digit:]]{2}-[[:digit:]]{2}\b' saradnici.txt
		
	
Slika 8. - Komanda koja pretražuje saradnike po godini rođenja, preko regularnih izraza.

Zapažamo argument -E (--extended-regexp), preko koga se uključuje upotreba regularnih izraza, zapažamo i 'dvostruku' pojavu argumenta \b (boundary), preko koga se u regularnim izrazima prepoznaju granice reči (tj. znakovi kao što su razmaci, tabovi, crte i drugi specijalni znaci koji ograničavaju pojedinačne reči), a pored navedenog, vidimo i to da se određene klase znakova (u programu grep), označavaju drugačije u odnosu na sintaksu koju smo prikazali u uvodnom članku o regularnim izrazima.

U većini drugih regex implementacija, klasa znakova preko koje se prepoznaju cifre, tipično se označava kao: \d, što znači da bi regularni izraz bio zapisan drugačije: 1981-\d{2}-\d{2}).

U svakom slučaju (u najopštijem smislu): potrebno je naći nisku koja počinje sa "1981", posle čega sledi crtica, zatim, dve cifre (koje praktično predstavljaju mesec), zatim, ponovo crtica i - na kraju - ponovo dve cifre (koje predstavljaju dan).

Prethodno definisana pretraga sada vraća jedinog kandidata koji je (zapravo) rođen navedene godine.

		
2 Dejan  Kovačević  30    admin     1981-03-21     1770
		
	
Slika 9. - Rezultat izvršavanja prethodne komande.

Ako se datumi pojavljuju u više kolona, situacija više nije jednostavna i potrebno je koristiti program koji je u stanju da pristupa pojedinačnim poljima u okviru reda, tako da budemo sigurni da se pretražuju podaci iz (npr) četvrte kolone, a ne podaci iz sedme kolone i sl. (što važi i za pretragu drugih formata koji se pojavljuju u više kolona).

Za zadatke kakve smo naveli (i druge komplikovanije zadatke), tipično se koristi kompleksniji program awk koji ćemo opisati kasnije u članku (uz odgovarajuće praktične primere).

Takođe, zadržaćemo se na jednostavnijim regex obrascima (i za grep, i za druge programe), da ne bismo skretali pažnju čitalaca sa principa funkcionisanja programa koje prikazujemo.

Dakle, ozbiljniji zahvati praktično zahtevaju upotrebu kompleksnijih programa (u članku ćemo koristiti program awk kome ćemo uskoro posvetiti više pažnje), međutim - kako to obično biva - upotreba moćnijih programa podrazumeva i upotrebu kompleksnije sintakse, i stoga se vredi zadržati na upotrebi programa grep za zadatke "manje i srednje težine", što ćemo dodatno pojasniti preko dosadašnjeg primera ....

U prvom slučaju, tražili smo redove sa podacima o administratorima sajta, a ako bi pored administratora (nivo privilegija 30), bilo potrebno pronaći i moderatore (nivo privilegija 20), i takav zadatak se može obaviti korišćenjem programa grep - pod uslovom da se pažljivo postupa po pitanju toga koji podatak treba koristiti kao kriterijum za pretragu.

Sledeća pretraga ....

		
$ grep -E 'admin|moderator' saradnici.txt 
		
	
Slika 10. - Pravilan način pronalaženja saradnika sa funkcijom admin, preko regularnih izraza.

.... vraća željeni rezultat, ali zato "idejno slična pretraga" nalik na sledeću pretragu ....

		
$ grep -E '20|30' saradnici.txt
		
	
Slika 11. - Nepravilan način pronalaženja saradnika sa funkcijom admin, preko regularnih izraza..

.... vraća vrlo diskutabilne rezultate, jer nimalo (!) nije teško zamisliti da niska "20" ili "30" može biti dan rođenja, deo niske id, ili deo nekog drugog podatka.

Međutim, postoje i drugi detalji o kojima se mora voditi računa.

Recimo, ako postoji šansa da se među email adresama pronađu podniske "admin" i "moderator" (npr. ukoliko postoje korisnici sa email adresama superadmin2000@gmail.com, veselimoderator@gmail.com i sl) - stvari se komplikuju.

U konkretnom primeru, gotovo je sigurno da se problem može rešiti uz upotrebu argumenta \b, ali, kao što smo već nagovestili, u (drugim) kritičnim situacijama, prepoznavanje sadržaja pojedinačnih polja (tj. kolona) u redovima, najsigurnije je obaviti preko programa awk.

Nešto kasnije, videćemo kako se preko programa awk može rešiti zadatak pronalaženja korisnika čiji je nivo privilegija veći ili jednak 20, ali, na ovom mestu vraćamo se na upoznavanje sa još nekoliko mogućnosti programa grep (nakon čega sledi poglavlje u kome ćemo se upoznati i sa osnovnim mogućnostima programa sed).

Numeracija redova

Uz argument -n (--line-number), komanda grep prikazuje i redne brojeve linija iz datoteke (na kojima dolazi do poklapanja):

		
$ grep -n 'admin' saradnici.txt

3:1 Milan  Jovanović  30    admin     1984-10-15     162
4:2 Dejan  Kovačević  30    admin     1981-03-21     1770
		
	
Slika 12. - Primer izvršavanja programa grep sa uključenom numeracijom redova.

Inverzija pretrage

Uz argument -v (--invert-match), pretraga vraća sve redove koji ne sadrže (pod)niske koje odgovaraju navedenom obrascu pretrage:

		
$ grep -E -v '\b19[[:digit:]]{2}\b' saradnici.txt

6 Nevena Katić      10    saradnik  2000-04-05     204628
		
	
Slika 13. - Primer izvršavanja programa grep sa inverzijom pretrage.

U gornjem primeru, videli smo pretragu koja vraća sve saradnike čije godište ne počinje sa "19" (u datoteci "saradnici.txt" pojavljuje se samo jedan takav saradnik).

Prikaz prethodnih redova

Uz argument -B (--before-context), posle čega sledi brojčana vrednost (na primer 2), rezultat sadrži - pored pronađenih redova - takođe i navedeni broj redova koji prethode pronađenim redovima.

		
$ grep -B2 '\b1985\b' saradnici.txt

3 Ivana  Marković   20    moderator 1986-11-01     18324
4 Petar  Komnenović 10    saradnik  1992-08-08     19427
5 Jelena Spasić     10    saradnik  1985-01-12     191981
		
	
Slika 14. - Prikaz redova koji prethode pronađenim redovima, preko argumenta "-B" (before).

Prikaz sledećih redova

Uz argument -A (--after-context), posle čega sledi brojčana vrednost (na primer 2), rezultat sadrži - pored pronađenih redova - takođe i navedeni broj redova koji slede posle pronađenih redova.

		
$ grep -A2 '\b1985\b' saradnici.txt

5 Jelena Spasić     10    saradnik  1985-01-12     191981
6 Nevena Katić      10    saradnik  2000-04-05     204628
7 Oliver Petrović   10    saradnik  1993-09-04     215283
		
	
Slika 15. - Prikaz redova koji slede posle pronađenih redova, preko argumenta "-A" (after)..

Naravno, prethodne dve opcije moguće je i kombinovati:

		
$ grep -B2 -A2 '\b1985\b' saradnici.txt

3 Ivana  Marković   20    moderator 1986-11-01     18324
4 Petar  Komnenović 10    saradnik  1992-08-08     19427
5 Jelena Spasić     10    saradnik  1985-01-12     191981
6 Nevena Katić      10    saradnik  2000-04-05     204628
7 Oliver Petrović   10    saradnik  1993-09-04     215283
		
	
Slika 16. - Kombinovanje opcija "-B" i "-A".

Sed - osnovna obrada teksta

Pošto smo se upoznali sa programom koji praktično predstavlja 'uobičajenu opciju' za pretragu teksta u Linux terminalu, upoznaćemo se i sa programima koji se tipično koriste za izmenu teksta i obavljanje drugih zadataka.

Program sed (Stream Editor), omogućava obavljanje raznovrsnih operacija nad ulaznim niskama, ali, u praksi se najčešće koristi za izmenu delova ulaznog teksta. *

Obrada teksta preko programa sed, izvršava se po sledećoj šemi:

		
$sed 'operacija/postojeći_obrazac/novi_tekst/' ulazna_datoteka
		
	
Slika 17. - Opšta šema izvršavanja programa sed.

Komande se zadaju unutar niske, a argument "operacija" označava jednu od mogućih internih komandi za obradu teksta.

Sam po sebi, sed je krajnje zanimljiv i prilično moćan program za obradu teksta, ali, za komplikovanije zahvate, u praksi se najčešće (ipak) koristi program awk (tema sledećeg poglavlja, i objektivno još moćniji program).

* Kao što smo prethodno nagovestili: u Linux terminalu (u uobičajenim situacijama), komanda grep praktično predstavlja ekvivalent opcije "search" (sa kakvom se inače srećemo u editorima teksta), dok je komanda sed praktično ekvivalent opcije "replace".

Pošto se program sed 'tipično'/najčešće koristi za zamenu delova teksta, pogledajmo za početak upravo jedan takav primer (interna komanda zadata je preko argumenta s koji označava zamenu ("s" - skraćeno od "substitute")):

		
$ sed 's/saradnik/operator/' saradnici.txt
		
	
Slika 18. - Primer zamene podniski preko programa sed.

Nakon izvršavanja komande, sve pojave niske "saradnik" zamenjene su niskom "operator", pri čemu se rezultat prikazuje u terminalu, a kada kažemo "u terminalu", na posredan način smo nagovestili da pozivi komandi grep i sed ne podrazumevaju * trajnu izmenu sadržaja ulazne datoteke!

Za trajno čuvanje - iako same komande nude mogućnost operisanja direktno nad sadržajem datoteka * (preko dodatnih opcija) - najpraktičnije je koristiti redirekciju:

		
$sed 's/postojeci_obrazac/novi_tekst/' ulazna_datoteka > nova_datoteka
		
	
Slika 19. - Primer redirekcije rezultata izvršavanja programa sed (to jest, praktično: upis podataka u datoteku).

* Dakle: postoji (inače) opcija direktnog operisanja nad datotekama, ali, tipično se I/O operacije sa datotekama obavljaju putem redirekcije.

Kad smo već kod praktičnosti, naveli smo da se za komplikovanije primere obrade najčešće koristi program awk, međutim, svakako želimo da zainteresujemo čitaoce da dodatno istražuju i program sed, i stoga ćemo prikazati još koji primer.

Recimo, ukoliko je potrebno ograničiti dejstvo komande sed na određeni raspon redova, može se koristiti opcija -n:

		
sed -n '3,10p;s/saradnik/operator/g' saradnici.txt
		
	
Slika 20. - Primer ograničavanja dejstva programa sed na raspon redova (između trećeg i desetog), preko argumenta "-n".

Ako pokrenemo poslednju komandu, zaglavlje se (faktički) preskače, što znači da će pretraga i zamena početi od 3. reda (praktično: u obzir će biti uzeti samo redovi koji sadrže slogove sa podacima).

U prethodnom primeru, znali smo da datoteka sadrži 10 redova, međutim, ponekad nećemo 'znati unapred' i, u takvim situacijama, komanda se može dodatno uopštiti uz navođenje znaka $, koji predstavlja oznaku za poslednji red:

		
sed -n '3,$;s/saradnik/operator/g' saradnici.txt
		
	
Slika 21. - Primer ograničavanja dejstva programa sed na raspon redova, od trećeg reda nadalje, preko argumenta "-n".

Zamena pronađenih obrazaca drugim niskama, jeste tipična namena programa sed, međutim, program se takođe može koristiti i za uklanjanje redova koji odgovaraju pronađenom obrascu (što se postiže preko interne komande d ('delete')),:

		
sed '/^[[:space:]]*$/ d' saradnici.txt
		
	
Slika 22. - Primer uklanjanja praznih redova preko programa sed.

Prethodno navedena komanda pronalazi - i uklanja - sve redove koji su prazni ili sadrže samo whitespace znakove.

AWK - napredna manipulacija tekstom

Kombinovanjem jednostavnih programa i tehnika koje smo do sada prikazali (programi grep i sed, redirekcija i sl), moguće je obaviti većinu svakodnevnih zadataka sa tekstom, ali, kada je u pitanju precizna i sveobuhvatna obrada teksta u Linux terminalu, "zvezda večeri" je program AWK.

U najpraktičnijem smislu, awk * je zapravo svojevrstan interpretator za specijalizovani programski jezik (sa C-olikom sintaksom, posebnim promenljivama, kontrolnim strukturama i ugrađenim funkcijama), i u pitanju je programski jezik koji je specifično namenjen (naprednoj) obradi teksta.

* Sama reč "AWK" je akronim sačinjen od početnih slova prezimena koautora programa: Alfred Aho, Peter J. Weinberger i Brian Kernighan.

Za početak, može se reći da izvršavanje programa awk funkcioniše po sledećem obrascu ....

		
$ awk obrazac { izvršne_komande } ulazna_datoteka
		
	
Slika 23. - Opšta šema izvršavanja programa awk.

.... ali, princip funkcionisanja lakše je razumeti uz primere (a opšta šema koju smo prethodno prikazali, uvek može biti nešto na šta ćete se vraćati povremeno, zarad boljeg razumevanja različitih konkretnih primera).

U prvom primeru, razmotrićemo situaciju u kojoj je potrebno izdvojiti samo one redove koji sadrže slogove sa saradnicima (i dalje se služimo podacima iz datoteke saradnici.txt), a prvo što nam može pasti na pamet, jeste to da se problem može rešiti upotrebom regularnih izraza.

Mi se "pravimo da ne znamo" da postoji elegantniji način, i pri tom se čitaoci takođe prave da ne naslućuju da postoji elegantniji način (a zapravo samo želimo da se nadovežemo na ideje koje smo već koristili, i da pokažemo da se regularni izrazi mogu koristiti i u programu awk (što npr. može biti "dobar" ili "jedini" obrazac pretrage u nekom drugom slučaju)).

Ako se filtracija redova obavlja preko regularnih izraza (u primeru koji razmatramo), biće pretraživani redovi koji počinju cifrom, a blok sa izvršnim komandama, podrazumeva ispis tri specifične kolone:

		
awk '/^[0-9]/ { printf("%s %s %s\n", $2, $3, $5) }' saradnici.txt
		
	
Slika 24. - Primer izdvajanja kolona (uz korišćenje regularnih izraza), iz redova koji počinju cifrom.

Komanda koju smo videli pruža priliku da se detaljnije pozabavimo strukturom instrukcija koje su argumenti programa awk: *

  • u prvom delu naredbe ("obrazac"), pojavljuje se regularni izraz ^[0-9], preko koga se prepoznaju linije koje počinju cifrom - i to su linije koje će program obrađivati (tj. drugim rečima - linije koje ne odgovaraju obrascu - biće zanemarene)
  • izvršne komande, oivičene vitičastim zagradama { .... }, obuhvataju (u primeru koji razmatramo), formatirani ispis nekoliko proizvoljno izabranih kolona preko komande printf (u pitanju je C-olika sintaksa, što naravno ne čudi, budući da je program awk razvijen u istoj "softverskoj kuhinji" kao i programski jezik C)
  • u (internoj) komandi printf, kao argumenti se koriste specijalne promenljive: $2, $3 i $5, koje odgovaraju poljima (tj. "kolonama") u redu koji se trenutno obrađuje, i praktično su u pitanju: ime ($2) i prezime saradnika ($3), kao i funkcija koju saradnik obavlja ($5)
  • kao ulaz, koristi se ista datoteka koju smo i do sada koristili u primerima

* Praktično je u pitanju mini-skripta za obradu teksta (a možemo primetiti da je program awk inače u stanju da pokreće i znatno veće "skripte" za obradu teksta, koje često nalikuju pravim programima).

Program uzima u obzir jednu po jednu liniju i, ukoliko nije naveden uslov (tj. "obrazac"), u obradi će biti korišćeni svi redovi.

U gornjem primeru, kao što smo već naveli - postoji uslov (obrazac pretrage koji određuje da se na izlaz šalju (samo) redovi koji počinju cifrom, što u praktičnom smislu znači: redovi sa podacima o saradnicima).

Postoji način (kao što ćemo videti u nastavku), da se kao kriterijum za izdvajanje koristi i broj polja u datom redu, kao i redni broj samog reda.

U svakom slučaju, kada linija dospe na obradu, ceo slog (tj. pojedinačni red ulaznog teksta), deli se preko niske koja je definisana kao separator (podrazumevani separatori su razmaci i tabovi, ali, mogu se definisati i proizvoljne niske), a u daljoj obradi, može se pristupati:

  • celom redu, preko promenljive $0
  • pojedinačnim poljima (tj. 'kolonama'), preko promenljivih $1, $2, $3 .... $n (gde n predstavlja indeks poslednje kolone)

.... pri čemu su definisane još dve korisne promenljive:

  • NF (Number of Fields) - ukupan broj polja (tj. kolona) u trenutnom redu
  • NR (Number of Records) - ukupan broj redova

Promenljive NR i NF mogu se koristiti i kao deo obrasca za proveru, koji prethodi izvršnim komandama za formatiranje (slede primeri) ....

Pošto smo sagledali dodatne opcije, jasno je da se slogovi sa podacima saradnika mogu izdvojiti mnogo lakše preko jednostavnog uslova NR>2 ("redni broj sloga veći od 2" (prva dva reda u tabeli predstavljaju formatirano zaglavlje)) ....

		
awk 'NR>2 { printf("%s %s %s\n", $2, $3, $5) }' saradnici.txt
		
	
Slika 25. - Primer izdvajanja kolona, iz redova sa rednim brojem koji je veći od 2 (ovoga puta, umesto regularnog izraza, koristi se uslov).

.... i rezultat je skoro isti kao u prvom pozivu.

Kažemo "skoro", jer biće ispisan i poslednji red koji je prazan, što, u praksi, verovatno (?!) ne predstavlja problem.

Program awk ne biva zakočen time što se pozivaju argumenti kao što su (na primer) $1, $4, ili $17 koji ne postoje u praznom redu, ali, ukoliko se izlaz šalje u drugi program - u kome bi pojava nepravilno formatiranog ulaza mogla dovesti do zastoja - potrebno je da budemo sasvim precizni.

U smislu 'povećanja preciznosti', lako se može urediti da se u rezultatu pojave samo redovi koji sadrže tekst (na primer, preko uslova koji proverava da li je ukupan broj polja u trenutnom redu (promenljiva NF), veći od 0): *

		
awk 'NR>2 && NF>0 { printf("%s %s %s\n", $2, $3, $5) }' saradnici.txt
		
	
Slika 26. - Primer izdvajanja kolona, iz redova sa rednim brojem koji je veći od 2 (pri čemu je broj polja u redu veći od 0).

* Promenljiva NF ima vrednost 0 u slučaju da je red prazan, a pitate se verovatno i zašto smo (o)stavili uslov NR>2?

U opštem smislu, može se reći da je krajnje uputno da se naredba napiše tako da program awk ne pretražuje redove za koje je unapred poznato da ne mogu sadržati bitne podatke (što se posebno odnosi na primere koji su (primetno) obimniji od primera koji smo prikazali).

Još je bolje ako se napiše uslov koji doslovno proverava da li red sadrži tačno onoliko kolona koliko je predviđeno (u našem slučaju 7):

		
awk 'NR>2 && NF==7 { printf("%s %s %s\n", $2, $3, $5) }' saradnici.txt
		
	
Slika 27. - Primer izdvajanja kolona, iz redova sa rednim brojem koji je veći od 2 (pri čemu se izdvajaju redovi koji imaju tačno 7 polja tj. kolona).

U daljoj obradi, preko prethodno izdvojenih podataka, lako se može uobličiti (na primer) SQL upit za unos sloga u bazu podataka:

		
printf("INSERT INTO saradnici (ime, prezime, funkcija) VALUES('%s', '%s', '%s');\n", $2, $3, $5)
		
	
Slika 28. - Primer korišćenja komande awk za formatiranje SQL upita.

Zarad preglednosti, prikazali smo samo deo sa komandom printf (ostatak je isti kao na prethodnoj slici).

"Da sve bude još bolje", izlaz se lako može pajpovati npr. u program preko koga se standardni ulaz prosleđuje u tekstualni clipboard operativnog sistema:

		
awk 'prethodni uslovi i printf' datoteka | xclip -selection clipboard
		
	
Slika 29. - Primer usmeravanja rezultata obrade prethodne komande u tekstualni clipboard operativnog sistema.

U većini situacija, programi koje smo do sada naveli: ls, cp, mv .... grep, sed i awk, tipično predstavljaju deo osnovnog paketa instaliranih programa na većini GNU/Linux distribucija, dok sa programom xclip to tipično nije slučaj, što znači da se program xclip (kao i mnogi drugi programi), mora instalirati zasebno.

Prikazaćemo prethodnu komandu i u celosti (iako je ponešto "glomazna"):

		
awk 'NR>2 && NF==7 { printf("INSERT INTO saradnici (ime, prezime, funkcija) VALUES (\"%s\", \"%s\", \"%s\");\n", $2, $3, $5) }' saradnici.txt | xclip -selection clipboard
		
	
Slika 30. - Prikaz komande za formatiranje SQL upita i slanje rezultata u clipboard (ovoga puta, komanda je prikazana u celosti).

Za kraj početnog upoznavanja sa komandom awk, * vratićemo se na primer pronalaženja korisnika iz tabele, čiji je nivo privilegija veći ili jednak 20 ....

Budući da program awk omogućava precizan pristup poljima u okviru reda (a pri tom raspolaže i strukturama za kontrolu toka programa), lako se može proveriti da li podatak u 4. koloni zadovoljava uslov koji je naveden u prethodnom pasusu ....

		
awk 'NR>2 && NF==7 && $4>=20 { printf("%s %s %s\n", $2, $3, $5) }' saradnici.txt
		
	
Slika 31. - Primer pronalaženja saradnika preko nivoa privilegija (administratori i moderatori).

.... pri čemu se (očekivano) dobija sledeći rezultat:

		
Milan Jovanović admin
Dejan Kovačević admin
Ivana Marković moderator
		
	
Slika 32. - Rezultat izvršavanja prethodne komande.

* Iskoristićemo komandu awk nadalje u ovom članku za nekoliko jednostavnih primera, a svakako ćemo se u narednim člancima upoznati i sa drugim opcijama komande awk.

U nastavku, razmotrićemo još i dve jednostavne komande za formatiranje izlaza.

Sort - uređivanje redova

Program sort koristi se za uređivanje redova ulaznog teksta shodno zadatom kriterijumu (uređivanje podrazumeva premeštanje redova jednih ispod drugih, a kriterijum je sadržaj nekog od polja).

Ako komanda awk ....

		
awk 'NR>2 && NF==7 { printf("%s %s %s\n", $2, $3, $6) }' saradnici.txt
		
	
Slika 33. - Primer korišćenja komande awk za ispis podataka o saradnicima (pri čemu će rezultat nadalje biti sortiran preko komande sort).

.... vrati sledeći izlaz ....

		
Milan Jovanović 1984-10-15
Dejan Kovačević 1981-03-21
Ivana Marković 1986-11-01
Petar Komnenović 1992-08-08
Jelena Spasić 1985-01-12
Nevena Katić 2000-04-05
Oliver Petrović 1993-09-04
Stojan Milić 1995-03-05
		
	
Slika 34. - Rezultat izvršavanja prethodne komande.

.... rezultat se može dodatno sortirati preko komande sort:

		
awk_prethodni | sort -k 3
		
	
Slika 35. - Primer sortiranja rezultata preko komande sort.

Argument -k 3 označava da se kao kriterijum za sortiranje koristi treća kolona (praktično, datum rođenja).

Tabela sada ima sledeći oblik:

		
Dejan Kovačević 1981-03-21
Milan Jovanović 1984-10-15
Jelena Spasić 1985-01-12
Ivana Marković 1986-11-01
Petar Komnenović 1992-08-08
Oliver Petrović 1993-09-04
Stojan Milić 1995-03-05
Nevena Katić 2000-04-05
		
	
Slika 36. - Rezultat izvršavanja prethodne komande.

Skoro smo gotovi i ostaje samo da povratimo tabelarni prikaz.

Column - tabelarno uređivanje unetog teksta

Program column može se koristiti za uspostavljanje (ili 'povratak') tabelarne strukture teksta (pri čemu je implicirano da je ulazni tekst formatiran tako da svaki red sadrži isti broj kolona, i tako da se u svakoj koloni nalazi podatak istog tipa).

Nakon pokretanja sledeće komande ....

		
poslednja_komanda_iz_prethodnog_odeljka | column -t
		
	
Slika 37. - Primer korišćenja komande column za uspostavljanje tabelarne strukture teksta.

.... dobija se sledeći rezultat:

		
Dejan  Kovačević  1981-03-21
Milan  Jovanović  1984-10-15
Jelena Spasić     1985-01-12
Ivana  Marković   1986-11-01
Petar  Komnenović 1992-08-08
Oliver Petrović   1993-09-04
Stojan Milić      1995-03-05
Nevena Katić      2000-04-05
		
	
Slika 38. - Rezultat izvršavanja prethodne komande.

Pred kraj, napravićemo malu digresiju u odnosu na uobičajenije "Linux komande" (s tim da je u pitanju veoma zanimljiva srodna tematika, sa kojom smo se već okvirno upoznali) ....

Obrada standardnog ulaza

U uvodnom članku predstavili smo protočnu obradu (tj. 'pajpovanje') kao jednu od najkorisnijih osnovnih tehnika u UNIX-olikim okruženjima, a na ovom mestu ćemo iskoristiti priliku da se upoznamo i sa time kako se u nekoliko programskih jezika mogu implementirati mehanizmi za 'prihvat i obradu' prosleđenih podataka.

Prikazani kodovi nisu (ipak) primereni upotrebi u produkcijskom okruženju, ali, smatramo da su sasvim dovoljno 'ilustrativni i informativni' za početno upoznavanje.

C/C++

U programskom jeziku C, obrada standardnog ulaza obavlja se preko FILE * pokazivača stdin koji je (u najpraktičnijem smislu) direktno povezan sa konzolnim ulazom operativnog sistema.

		
#include <stdio.h>
#define VELICINA_BAFERA 256

int main()
{
	char pajpovani_tekst[VELICINA_BAFERA + 1];
	char c;
	int i = 0;

	while ((c = fgetc(stdin)) != EOF) {
		pajpovani_tekst[i] = c;
		i++;
	}

	pajpovani_tekst[i] = 0;

	printf("%s", pajpovani_tekst);

	return 0;
}
		
	
Slika 39. - Primer obrade standardnog ulaza u programskom jeziku C.

U programskom jeziku C++, isti zadatak obavlja se preko objekta cin.

		
#include <iostream>

int main(int argc, char *argv[]) {
	std::string pajpovani_tekst;

	while (!std::cin.eof()) {
		std::string linija;
		getline(std::cin, linija);
		pajpovani_tekst += linija + "\n";
	}

	std::cout << pajpovani_tekst;

	return 0;
}
		
	
Slika 40. - Primer obrade standardnog ulaza u programskom jeziku C++.

Node JS (JavaScript)

U okruženju Node.js, objekat process sadrži (pod)objekte sa informacijama o trenutno pokrenutom Node.js procesu, * i pri tom se jedan od podobjekata, stdin, može koristiti za obradu standardnog ulaza. **

		
let pajpovani_tekst = "";

process.stdin.on("readable", () => {
	let deo_teksta;
	while ((deo_teksta = process.stdin.read()) !== null) {
		pajpovani_tekst += deo_teksta;
	}
});

process.stdin.on("end", () => {
	process.stdout.write(pajpovani_tekst);
});
		
	
Slika 41. - Primer obrade standardnog ulaza u radnom okruženju Node JS.

* Nisu u pitanju samo 'jednosmerne informacije', tj. preko objekta process može se uticati na različite parametre trenutno pokrenutog Node.js procesa (videti sledeću napomenu).

** Pored objekta stdin, postoji npr. i objekat stdout, preko koga se tekst može poslati na standardni izlaz, i sl.

Python

U Python-u, za obradu standardnog ulaza koristi se objekat stdin (iz modula sys).

		
import sys

pajpovani_tekst = ""

while True:
	red = sys.stdin.readline()

	if not red:
		break

	pajpovani_tekst += red

print(pajpovani_tekst)
		
	
Slika 42. - Primer obrade standardnog ulaza u programskom jeziku Python.

Sledeći koraci ....

Posle čitanja članka, reklo bi se da čitaocima predstoji poveći (ali veoma zabavan, zanimljiv i pre svega koristan), posao otkrivanja dodatnih opcija komandi koje su do sada nabrojane, kao i otkrivanje drugih programa za obradu teksta.

Na primer: da li postoje programi koji su u stanju da preprave proizvoljno formatirani izvorni kod (iz nekog programskog jezika), tako da budu uvaženi određeni obrasci uvlačenja redova i pozicioniranja vitičastih zagrada u odnosu na ostatak koda?!

Saznajte! :)

Pored navedenog - možete se oprobati i u kreiranju sopstvenih programa za obradu teksta, pri čemu će (za početak) Python ili Node.js poslužiti više nego dobro pri realizaciji takvih programa, budući da se bilo koja Python skripta ili Node.js skripta (kao što smo videli u prošlom poglavlju), lako može osposobiti za čitanje standardnog ulaza.

U sledećem članku, bavićemo se pisanjem shell skripti za automatizaciju procesa (a upoznaćemo se i sa nekoliko programa o kojima do sada nismo pisali) ....

Autor članka Nikola Vukićević Za web portal codeblog.rs
Napomena: Tekstovi, slike, web aplikacije i svi ostali sadržaji na sajtu codeblog.rs (osim u slučajevima gde je drugačije navedeno) predstavljaju intelektualnu svojinu autora sajta codeblog.rs i zabranjeno je njihovo korišćenje na drugim sajtovima i štampanim medijima, kao i bilo kakvo drugo korišćenje u komercijalne svrhe, bez eksplicitnog pismenog odobrenja autora.
© 2020-2026. Sva prava zadržana.
Facebook LinkedIn Twitter Viber WhatsApp E-mail
početna > Članci > GNU/Linux - 3. deo – Napredne komande
codeBlog codeBlog
Sajt posvećen popularizaciji kulture i veštine programiranja.
Napomena: Tekstovi i slike na sajtu codeblog.rs (osim u slučajevima, gde je drugačije navedeno) predstavljaju intelektualnu svojinu autora sajta codeblog.rs i zabranjeno je njihovo korišćenje na drugim sajtovima i štampanim medijima, kao i bilo kakvo drugo korišćenje u komercijalne svrhe, bez eksplicitnog odobrenja autora.
© 2020-2026. Sva prava zadržana.
Facebook - logo
Instagram - logo
LinkedIn - logo
Twitter - logo
E-mail
Naslovna
   •
Uslovi korišćenja
   •
Obaveštenja
   •
FAQ
   •
Kontakt