wc, uniq i tr — brojanje, uklanjanje duplikata i zamena znakova
Tri komande koje same za sebe ne rade skoro ništa. Ali se u lancu sa grep i sort pojavljuju toliko često da bez njih gotovo nijedna ozbiljna obrada teksta ne prolazi.
Redom: wc broji, uniq uklanja ponavljanja,
tr menja pojedinačne znakove.
wc — brojanje
$ wc /var/log/syslog 4821 58394 512847 /var/log/syslog
Tri broja: redovi, reči, bajtovi. U praksi ti skoro uvek treba samo jedan:
$ wc -l /var/log/syslog 4821 /var/log/syslog $ wc -w esej.txt 1247 esej.txt $ wc -c slika.png 248391 slika.png
Opcija -c broji bajtove, a -m znakove. Na
ćiriličnom ili bilo kom tekstu sa našim slovima to nije isto:
$ echo -n "džemper" | wc -c 9 $ echo -n "džemper" | wc -m 7
Slovo ž u UTF-8 zauzima dva bajta. Kad brojiš znakove,
koristi -m.
Trik sa imenom fajla
$ wc -l spisak.txt 42 spisak.txt $ wc -l < spisak.txt 42
Kad se koristi preusmeravanje, wc ne zna ime fajla pa ga ne
ispisuje. Neophodno kad rezultat ide u promenljivu:
$ broj=$(wc -l < spisak.txt) $ echo "Redova: $broj" Redova: 42
Više o razlici između < i imena fajla kao argumenta ima na
stranici Piping i
redirekcija.
Zamka: wc -l ne broji redove nego znakove za novi red
$ printf "prvi\ndrugi\ntreci" > bez-kraja.txt $ wc -l bez-kraja.txt 2 bez-kraja.txt $ cat bez-kraja.txt prvi drugi treci
Vidiš tri reda, wc kaže dva. Poslednji red nema znak za novi
red na kraju, pa se ne broji. Ovo se dešava sa fajlovima koje je napravio
Windows program ili neuredna skripta.
Otporna varijanta, koja broji i takav poslednji red:
$ grep -c "" bez-kraja.txt 3
Brojanje fajlova
$ ls /etc | wc -l 198
Radi, ali ne broji skrivene fajlove i puca ako neko ime sadrži znak za novi red. Pouzdanije je preko find:
$ find /etc -maxdepth 1 -type f | wc -l 83 $ find /var/log -type f -name "*.log" | wc -l 27
Više fajlova odjednom
$ wc -l *.txt
42 spisak.txt
128 beleske.txt
9 todo.txt
179 total
Red total na kraju je česta greška u skriptama — ako računaš
sa poslednjim redom kao rezultatom, dobićeš zbir umesto broja za poslednji
fajl.
uniq — uklanjanje ponavljanja
Najvažnija stvar na celoj stranici: uniq uklanja samo
susedne duplikate. Ako isti red stoji na dva mesta u fajlu a između
njih ima nečeg drugog, uniq ga neće primetiti.
$ cat imena.txt ana marko ana petar marko $ uniq imena.txt ana marko ana petar marko
Ništa se nije desilo. Zato uniq gotovo nikad ne stoji sam,
nego iza sort:
$ sort imena.txt | uniq ana marko petar
Za ovaj konkretan slučaj postoji i kraći zapis:
$ sort -u imena.txt ana marko petar
-c — brojanje pojavljivanja
Ovo je razlog zbog kog uniq uopšte postoji, jer to
sort -u ne ume:
$ sort imena.txt | uniq -c
2 ana
2 marko
1 petar
Sortiranje po učestalosti, opadajuće, dobija se drugim prolazom kroz
sort:
$ sort imena.txt | uniq -c | sort -rn
2 ana
2 marko
1 petar
Ovaj obrazac — sort | uniq -c | sort -rn — vredi zapamtiti
napamet. To je najbrži način da iz bilo kog loga saznaš šta se najčešće
dešava:
$ awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -5
4821 203.0.113.45
1203 198.51.100.7
847 192.0.2.19
412 203.0.113.88
198 198.51.100.23
Prva kolona pristupnog loga je IP adresa, pa je ovo spisak najaktivnijih posetilaca. Kolone izdvaja awk, a isto bi uradio i cut.
-d i -u — samo duplikati ili samo jedinstveni
$ sort imena.txt | uniq -d ana marko $ sort imena.txt | uniq -u petar
Praktična primena — pronalaženje duplih korisničkih imena ili istih
UID-ova u /etc/passwd:
$ cut -d: -f3 /etc/passwd | sort | uniq -d 1001
Prazan ispis znači da je sve u redu. Ako nešto ispiše, dva korisnika dele isti UID, što je stvarni bezbednosni problem.
Ignorisanje dela reda
$ uniq -i imena.txt # ne razlikuje velika i mala slova $ uniq -f 2 log.txt # preskoči prve dve kolone $ uniq -s 16 log.txt # preskoči prvih 16 znakova
Opcija -s je zlata vredna kod logova, gde svaki red počinje
vremenskom oznakom pa nijedna dva reda nisu identična:
$ cut -c17- /var/log/syslog | sort | uniq -c | sort -rn | head -3
284 systemd[1]: Started Session 42 of user alen.
112 kernel: [UFW BLOCK] IN=eth0 OUT=
47 cron[891]: (root) CMD (/usr/local/bin/backup.sh)
tr — zamena i brisanje znakova
tr radi nad pojedinačnim znakovima, ne nad rečima ni
obrascima. Za obrasce postoji sed.
Prva stvar koja iznenađuje: tr ne prima ime fajla.
Isključivo čita sa standardnog ulaza.
$ tr 'a' 'A' spisak.txt tr: extra operand 'spisak.txt' $ tr 'a' 'A' < spisak.txt $ cat spisak.txt | tr 'a' 'A'
Oba poslednja oblika rade; prvi je efikasniji jer ne pokreće još jedan proces.
Zamena
$ echo "linux je zabavan" | tr 'a-z' 'A-Z' LINUX JE ZABAVAN
Čitljivije, preko imenovanih skupova:
$ echo "LINUX" | tr '[:upper:]' '[:lower:]' linux
Skupovi koje ćeš koristiti: [:alpha:], [:digit:],
[:alnum:], [:space:], [:punct:].
Zamena razmaka novim redom, čime se rečenica pretvara u spisak:
$ echo "jedan dva tri" | tr ' ' '\n' jedan dva tri
-d — brisanje
$ echo "tel: 013-345-678" | tr -d '[:alpha:] :-' 013345678
Najkorisnija primena je uklanjanje Windows znakova za kraj reda:
$ file skripta.sh skripta.sh: Bourne-Again shell script, ASCII text, with CRLF line terminators $ tr -d '\r' < skripta.sh > /tmp/cisto.sh && mv /tmp/cisto.sh skripta.sh
Obrati pažnju na privremeni fajl. Ovo bi uništilo podatke:
$ tr -d '\r' < skripta.sh > skripta.sh # NE!
Shell isprazni odredišni fajl pre nego što tr uopšte krene,
kao što je objašnjeno u lekciji
Piping i redirekcija.
-s — sabijanje ponavljanja
$ echo "previse razmaka ovde" | tr -s ' ' previse razmaka ovde
Nezamenljivo pre obrade po kolonama, jer cut -d' ' svaki
višak razmaka tretira kao praznu kolonu:
$ df -h | tr -s ' ' | cut -d' ' -f1,5 Filesystem Use% /dev/sda2 38% /dev/sda3 63%
-c — sve osim navedenog
$ echo "Pozovi 013-345-678 danas" | tr -cd '[:digit:]\n' 013345678
Čita se: obriši sve što nije cifra ili novi red. Kombinacija
-cd je najbrži način da se iz teksta izvuku samo brojevi.
Sve tri zajedno
Klasičan zadatak — najčešće reči u tekstu:
$ tr -cs '[:alpha:]' '\n' < esej.txt | tr '[:upper:]' '[:lower:]' | sort | uniq -c | sort -rn | head -5
142 i
98 je
67 se
41 linux
38 na
Korak po korak: prvi tr pretvara sve što nije slovo u novi
red i sabija ponavljanja, drugi svodi na mala slova, sort grupiše,
uniq -c broji, drugi sort ređa opadajuće.
Šest komandi, nijedna ne zna šta je „reč" — a rezultat je frekvencijski rečnik. To je cela ideja Linuxa u jednom redu.
Još jedan koristan lanac — provera koliko je jedinstvenih IP adresa pokušalo prijavu preko SSH-a:
$ grep "Failed password" /var/log/auth.log | awk '{print $(NF-3)}' | sort -u | wc -l
47
Sitnice
Generisanje slučajne lozinke
$ tr -cd '[:alnum:]' < /dev/urandom | head -c 16; echo Kf3mZq8xTn2pWbLd
/dev/urandom je beskonačan izvor slučajnih bajtova;
tr propušta samo slova i cifre, a head -c
zaustavlja posle šesnaest znakova.
Kada je awk bolji izbor
Ako ti treba brojanje po uslovu, a ne po celom redu, lanac
sort | uniq -c je zaobilazan:
$ awk '{brojac[$1]++} END {for (i in brojac) print brojac[i], i}' access.log | sort -rn | head
Brže je na velikim fajlovima jer ne zahteva sortiranje. Ali je i teže za
čitanje — a lanac sa uniq pamtiš i posle godinu dana.
Kratka referenca
wc
-lredovi ·-wreči ·-cbajtovi ·-mznakoviwc -l < fajl— bez ispisa imena fajlagrep -c ""— brojanje redova otporno na fajl bez završnog novog reda
uniq (zahteva prethodno sortiranje)
-c— prebroj pojavljivanja-d— samo duplikati ·-u— samo jedinstveni-i— bez razlike velikih i malih slova-f N/-s N— preskoči N kolona / znakovasort -u— kraće kad ti treba samo uklanjanje duplikata
tr (čita samo sa standardnog ulaza)
tr 'a' 'b'— zameni znakove-d— obriši navedene znakove-s— sabij ponovljene znakove u jedan-c— primeni na sve osim navedenih[:upper:],[:lower:],[:digit:],[:alnum:],[:space:]
Vežba
$ cd /var/log
- Prebroj koliko redova u
syslogsadrži rečerror, bez obzira na velika i mala slova. - Izlistaj pet korisnika sa najviše prijava u
auth.log, sortirano po broju. - Iz fajla
/etc/passwdizdvoj sve različite shell-ove koje korisnici koriste, sa brojem korisnika po svakom. - Napravi fajl sa nekoliko redova koji imaju višak razmaka, pa ga očisti tako da između reči ostane po jedan razmak.
- Utvrdi koliko ukupno različitih reči ima u fajlu
/etc/services, bez razlike velikih i malih slova.
Peti zadatak traži sve tri komande u jednom lancu.
Komande sa kojima se ove tri najčešće spajaju su grep, sort, cut i awk, a način spajanja objašnjen je u lekciji Piping i redirekcija.
Cela lekcija je deo vodiča Linux osnove.
Comments
Post a Comment