AWK

Το awk είναι μία γλώσσα προγραμματισμού γενικού σκοπού και χρησιμοποιείται για σύντομα προγράμματα.Είναι ιδιαίτερα χρήσιμη για επεξεργασία γραμμών και πεδίων με απλό τρόπο. Μοιάζει αρκετά με τη C. Σε συνδυασμό με τα άλλα εργαλεία του Unix μπορούμε να υλοποιήσουμε πολλά πράγματα δηλαδή να φτιάξουμε δικά μας εργαλεία ακόμα τα ίδια του Unix.

awk '{print $1}' επιστρέφει το πρώτο πεδίο σε μία γραμμή.

Το ίδιο αποτέλεσμα μπορούμε να πετύχουμε με την εντολή cut -f1.

Αν γράψουμε awk '{print $1}' file4 όπου το file4 είναι :
John		274933
Jack		123578
Nick		958924	
Mary		100568
θα πάρουμε σαν έξοδο μόνο το πρώτο πεδίο κάθε γραμμής δηλαδή :
John
Jack
Nick
Mary
Αν το πρόγραμμά μας είναι αρκετά μεγάλο μπορούμε να το γράψουμε σε κάποιο αρχείο. Έτσι αν αυτό είναι το program1 η παραπάνω εντολή θα μπορούσε να γραφτεί awk -f program1 file4.

Η εντολή print $2 επιστρέφει το δεύτερο πεδίο ενώ η εντολή print $NF επιστρέφει το τελευταίο πεδίο και η print $(NF-1) το προτελευταίο πεδίο.

Αντίστοιχα με τη χρήση της cut θα είχαμε :
Print $2--------cut -f2
Print $NF------rev | cut - f1 | rev
Print $(NF-1)--rev | cut - f2 | rev

Αν δώσουμε την εντολή rev file4 | cut -f1 | rev τότε θα παίρναμε διαδοχικά :

rev file4
339472	nhoJ
875321	kcaJ
429859	kciN	
865001	yraM
rev file4 |cut -f1
339472
875321	
429859
865001
rev file4 | cut -f1 | rev
274933
123578
958924	
100568
Παρατηρούμε εδώ ότι η χρήση της awk είναι πιο εύκολη και μας βοηθάει όταν αυτό που ζητάμε είναι περίπλοκο να γίνει με τα έτοιμα εργαλεία του Unix.

Με τη χρήση της awk μπορούμε να μετρήσουμε τον αριθμό των πεδίων που υπάρχουν σε κάθε γραμμή με την εντολή print NF.
Αν file5 το παρακάτω αρχείο :
John	274933	Agias Sofias 91
Jack	123578	Mhtropolews	23
Nick	958924	Proksenou Koromhla 156
Mary	100568	Tsimiskh 40
τότε η εντολή awk '{print NF}' file5 θα μας επιστρέψει :
5
4
5
4
Αν έχουμε ένα αρχείο που έχει δύο πεδία, μία λέξη και τον αριθμό των φορών που εμφανίζεται σε ένα αρχείο για παράδειγμα το file6:
1 frequencies
5 god
23 the
7 or
2 numerical
...
Η εντολή awk '$1 > 100' file6 θα μας επιστρέψει τις γραμμές εκείνες όπου το πρώτο πεδίο είναι μεγαλύτερο του 100 δηλαδή θα μας επιστρέψει τις πιο συνηθισμένες λέξεις στο κείμενο. Τα ίδια αποτελέσματα θα είχαμε και με τις εντολές :
awk '$1>100 {print $0}' file6 και awk '$1>100 {print}' file6

Η δήλωση print $0 σημαίνει να τυπώσει ολόκληρη τη γραμμή και όχι κάποιο πεδίο όπως είδαμε προηγουμένως.

Η εντολή awk 'length > 50' file θα μας επιστρέψει τις γραμμές του file που έχουν μήκος πάνω από 50 χαρακτήρες ενώ η εντολή awk 'length($2) > 10' file θα μας επιστρέψει τις γραμμές του file όπου το μήκος του δεύτερου πεδίου είναι πάνω από 10 χαρακτήρες.

Για να βρούμε τη γραμμή στο αρχείο file που έχει το μεγαλύτερο μήκος θα χρησιμοποιήσουμε το παρακάτω πρόγραμμα :
awk '{ if (length($0) > max) max = length($0) }
END { print max }' file


Η εκτύπωση των πεδίων ενός αρχείου σε ανάποδη σειρά μπορεί να γίνει με την εντολή :
awk '{ for (i = NF; i > 0; --i) print $i }' file

Λέξεις που διαβάζονται και ανάποδα

Ένας πολύ έξυπνος συνδυασμός των εργαλείων του Unix και της awk μας επιτρέπει να βρούμε λέξεις οι οποίες διαβάζονται και ανάποδα.
Έτσι αν file7 το παρακάτω αρχείο :
genesis
A
god
O     
anna
your
did
noon
string
anna
τότε με τις εντολές sort -u file7 < file8 και rev < file8 | paste - file8 | awk '$1= =$2' θα μας επιστρέψει διαδοχικά :

Υπενθυμίζουμε ότι η sort -u ταξινομεί τις γραμμές ενός αρχείου και απαλείφει τις ίδιες γραμμές δηλαδή είναι ίδια με την sort file7 | uniq.

sort -u file7 < file8
A
O
anna
did
genesis
god
noon
string
your
rev < file8
A
O
anna
did
siseneg
dog
noon
gnirts
ruoy
H εντολή paste - file8 θα κάνει paste την είσοδο που πήραμε από το rev < file8 με το file8 δηλαδή : rev < file8 | paste - file8
A	A
dog	god
O	O
anna	anna
ruoy	your
did	did
noon	noon
gnirts	string
Η εντολή awk '$1= =$2' θα μας επιστρέψει τις γραμμές όπου το πρώτο πεδίο είναι ίσο με το δεύτερο.

rev < file8 | paste - file8 | awk '$1= =$2'
A	A
O	O
anna	anna
did	did
noon	noon
Αν θέλαμε μόνο το ένα πεδίο τότε θα γράφαμε :
rev < file8 | paste - file8 | awk '$1= =$2 {print $1}'
A
O
anna
did
noon
Ένας άλλος τρόπος για να πετύχουμε το παραπάνω λίγο πιο περίπλοκος είναι :
rev < file8 | cat - file8 | sort | uniq -c | awk '$1>=2 {print $2}' διαδοχικά:

rev < file8
A
O
anna
did
siseneg
dog
noon
gnirts
ruoy
H εντολή cat - file8 θα προσθέσει στο τέλος της εξόδου του rev < file8 το file8 δηλαδή :
rev < file8 | cat - file8
A
O
anna
did
siseneg
dog
noon
gnirts
ruoy
A
O
anna
did
genesis
god
noon
string
your
rev < file8 | cat - file8 | sort | uniq -c
2	A
2	O
2 	anna
2	did
1	dog
1	genesis
1	gnirts
1	god
2	noon
1	ruoy
1	siseneg
1	string
1	your
rev < file8 | cat - file8 | sort | uniq -c | awk '$1>=2 {print $2}
A
O
anna
did
noon

Σύγκριση δύο αρχείων

(Λέξεις που υπάρχουν στο ένα και όχι στο άλλο)

Έστω ότι έχουμε δύο αρχεία το file9 και file10 όπου :
file9		file10
genesis		windows
bible		system
live		university	
grep		bible
bible		library
unix		office
linux		unix
server		university
Αρχικά μετατρέπουμε τα δύο αρχεία ως εξής :
sort -u file9 >f9
sort -u file10 > f10
f9		f10
bible		bible
genesis		library
grep		office
linux		system
live		university
server		unix
unix		windows
Αν θέλουμε να βρούμε τις κοινές λέξεις που υπάρχουν στα δύο αρχεία τότε θα δώσουμε την εντολή :
cat f9 f10 | sort | uniq -c | awk '$1>=2 {print $2}' διαδοχικά :

cat f9 f10
bible
genesis
grep
linux
live
server
unix
bible
library
office
system
university
unix
windows
cat f9 f10 | sort | uniq -c
2 bible
1 genesis
1 grep
1 library
1 linux
1 live
1 office
1 server
1 system
1 university
2 unix
1 windows
cat f9 f10 | sort | uniq -c | awk '$1>=2 {print $2}'
bible
unix
Αν διοχετεύσουμε το αποτέλεσμα της παραπάνω εντολής σε ένα αρχείο f11 δηλαδή δώσουμε την εντολή cat f9 f10 | sort | uniq -c | awk '$1>=2 {print $2}' > f11 και μετά γράψουμε cat f9 f11 | sort | uniq -c | awk '$1= =1 {print $2}' τότε θα πάρουμε τις λέξεις που υπάρχουν στο αρχείο f9 αλλά όχι στο f10 δηλαδή το αποτέλεσμα θα ήταν :
genesis
grep
linux
live
server

Εύρεση και αριθμός λέξεων που έχουν συγκεκριμένη κατάληξη

Αν θέλουμε να βρούμε τις λέξεις σε ένα αρχείο (με κάθε γραμμή να έχει μία λέξη) που έχουν κατάληξη π.χ -e τότε θα δώσουμε την εντολή awk '$0 ~ /e$/' file. Έτσι αν δώσουμε awk '$0 ~ /e$/' file9 θα πάρουμε σαν έξοδο :
bible
live
bible
Παρατηρούμε ότι μπορούμε να χρησιμοποιήσουμε regular expressions όπως αυτές περιγράφηκαν σε άλλα εργαλεία του Unix.
Αν θέλουμε να μετρήσουμε τις λέξεις που τελειώνουν σε -e τότε θα δίναμε την εντολή awk '$0 ~ /e$/ {x=x+1} END {print x}' file 9 και θα παίρναμε 3.

Ένας άλλος τρόπος είναι η εντολή : sort file9 | uniq -c | awk '$2 ~ /e$/ {x=x+$1} END {print x}' όπου διαδοχικά έχουμε :

sort file9 | uniq -c
2 bible
1 genesis
1 grep
1 linux
1 live
1 server
1 unix
Έτσι έχουμε για κάθε διαφορετική λέξη μία εγγραφή που μας λέει στην πρώτη στήλη πόσες φορές εμφανίζεται και στη δεύτερη περιέχει τη λέξη. Έτσι αρκεί να βρούμε ποιες λέξεις τελειώνουν σε -e και να προσθέσουμε σε μία μεταβλητη x τον αριθμό της πρώτης στήλης όπου αυτό ακριβώς κάνει το πρόγραμμα awk.

Αν δεν θέλαμε να μετράνε οι λέξεις που εμφανίζονται πάνω από μία φορά τότε θα δίναμε την εντολή sort -u file9 | awk '$0 ~ /e$/ {x=x+1} END {print x}' και θα παίρναμε σαν αποτέλεσμα το 2.

Άλλοι δύο τρόποι για να πετύχουμε να μετρήσουμε λέξεις που τελειώνουν σε -e χωρίς τη χρήση awk και χωρίς να υποθέσουμε ότι στο αρχείο κάθε γραμμή είναι μία λέξη είναι οι παρακάτω :
tr -sc 'A-Za-z' '\012' < file9 | grep 'e$' | wc -l για όλες τις λέξεις
tr -sc 'A-Za-z' '\012' < file9 | grep 'e$' | sort | uniq -c | wc -l

Μπορούμε τα δύο προγράμματα σε awk που φτιάξαμε να τα ενώσουμε σε ένα και έτσι παράλληλα να δούμε και επιπλέον ιδιότητες της awk.
sort file9 | uniq -c | awk '$2 ~ /e$/ { x = x +$1; y = y+1} END {print x,y}'
ή
sort file9 | uniq -c | awk '$2~/e$/ {x += $1; y++} END {print x,y}'

To uniq -c με χρήση της awk

Υπενθυμίζουμε ότι το uniq -c επιστρέφει εγγραφές όπου έχουν δύο πεδία. Στο πρώτο πεδίο είναι ένας αριθμός που μετράει πόσες ίδιες λέξεις υπάρχουν στη σειρά σε ένα αρχείο δηλαδή σε διαδοχικές γραμμές όπου στο αρχείο κάθε λέξη είναι και γραμμή. Στη δεύτερη στήλη περιλαμβάνεται η λέξη στην οποία αντιστοιχεί ο αριθμός. Η uniq -c χρησιμοποιείται σε συνδυασμό με την sort. Έστω το αρχείο f12 όπου :
f12
unix
linux
company
computer
unix
cd
linux
unix
bible
Με την εντολή :

sort f12 | awk '$0 = = prev {c++}
$0!=prev {print c,prev c=1 prev=$0}
END {print c,prev}'


θα έχουμε αποτέλεσμα ίδιο με αυτό της εντολής sort f12 | uniq -c δηλαδή υλοποιήσαμε με awk την εντολή uniq -c. Έτσι το αποτέλεσμα θα είναι :
1 bible
1 cd
1 company
1 computer
2 linux
3 unix
 
Αρχικά η εντολή sort f12 παράγει το αποτέλεσμα :
bible
cd
company
computer
linux
linux
unix
unix
unix
Κατόπιν το πρόγραμμα awk ελέγχει κάθε γραμμή αν είναι ίδια με την προηγούμενη ($0 = = prev). Αν είναι ίδια τότε αυξάνει τη μεταβλητή c κατά ένα που κρατάει τον αριθμό των φορών που εμφανίζεται η λέξη διαδοχικά. Αν δεν είναι ίδια τότε εκτυπώνει το αποτέλεσμα δηλαδή τον αριθμό και τη λέξη. Στο τέλος του προγράμματος εκτυπώνεται το αποτέλεσμα της τελευταίας επανάληψης γιατί αν παραλείπαμε την τελευταία εντολή δεν θα εκτυπωνόταν το αποτέλεσμα για την τελευταία λέξη.

Συχνότητες λέξεων

Χρησιμοποιώντας την awk μπορούμε να μετρήσουμε συχνότητες λέξεων χωρίς να απαιτείται η χρήση της sort. Αυτό μπορούμε να το πετύχουμε με πίνακες οι οποίοι όπως θα δούμε έχουν σημαντικές δυνατότητες. Κατ' αρχήν χωρίς τη χρήση awk μπορούμε να μετρήσουμε για κάθε λέξη πόσες φορές εμφανίζεται στο αρχείο με την εντολή :

tr -sc 'A-Za-z' '\012' < file | sort | uniq -c

Με χρήση της awk η αντίστοιχη εντολή είναι :

Tr -sc 'A-Za-z' '\012' < file | awk
'{freq[$0]++};
END {for (w in freq) print freq[w],w}'


Παρατηρούμε ότι οι πίνακες στην awk είναι πραγματικοί hashtables αφού παίρνουν αλφαριθμητικά σαν κλειδιά όπως φαίνεται από το παράδειγμα όπου έχουμε freq[$0] όπου $0 είναι αλφαριθμητικό. Έτσι το παραπάνω πρόγραμμα βάζει σε κάθε θέση του πίνακα τον αριθμό των φορών που εμφανίζεται η αντίστοιχη λέξη αφού κάθε φορά που βρίσκει μία αυξάνει τον αντίστοιχο δείκτη freq[w]++. Στο τέλος εκτυπώνονται τα περιεχόμενα του πίνακα και παίρνουμε τα ανάλογα αποτελέσματα. Επίσης παρατηρούμε ότι δεν χρειάζεται να δηλώσουμε το μέγεθος του πίνακα αφού μία από τις ιδιότητες του είναι να μεγαλώνει όσο χρειάζεται.
Η τελευταία λύση για μέτρηση συχνοτήτων είναι καλύτερη γιατί δεν χρειάζεται να έχουμε ταξινομημένο το αρχείο για να εφαρμόσουμε το πρόγραμμα μας όπως στο προηγούμενο παραδειγμα.

Συγχώνευση γραμμών που έχουν κοινό πεδίο

Έστω ότι έχουμε ένα αρχείο file13 το οποίο έχει δύο πεδία σε κάθε γραμμή. Έστω ότι το αρχείο προήλθε από μία εντολή sort file | uniq -c και είναι το έξής :
file13
2 bible
1 cd
1 company
1 computer
2 linux
3 unix
Θέλουμε να παράγουμε μία έξοδο που σε κάθε γραμμή θα έχει στο πρώτο πεδίο ένα αριθμό και μετά θα έχει τόσα πεδία ανάλογα με τις λέξεις που έχουν συχνότητα ίση με αυτή του πρώτου πεδίου. Επειδή τα λόγια πολλές φορές είναι ανούσια και δεν είναι κατανοητά ένα παράδειγμα θα μας πείσει τι θέλουμε να πετύχουμε. Αυτό που επιδιώκουμε είναι να έχουμε μία έξοδο όπως την παρακάτω :
1	cd	company	computer
2	bible	linux
3	unix
H εντολή που θα μας δώσει το παραπάνω αποτέλεσμα είναι η εξής :

Sort file13 | awk '$1= = prev {list = list " " $2}
$1!= prev {if(list) print list
list=$0
prev=$1}
END {print list}'


ή

Sort file13 | awk '$1= = prev {printf "\t %s", $2}
$1!= prev {prev = $1
printf "\n %s \t %s", $1, $2}
END
{printf "\n"}'


Αρχικά η εντολή sort file13 μας δίνει το αποτέλεσμα :
1 cd
1 company
1 computer
2 bible
2 linux
3 unix
Τα δύο προγράμματα awk λειτουργούν σχεδόν με τον ίδιο τρόπο. Απλά το πρώτο χρησιμοποιεί μια παραπάνω μεταβλητή, τη list η οποία περιέχει κάθε φορά τη γραμμή που πρέπει να εκτυπωθεί. Έτσι αν το πρώτο πεδίο της τρέχουσας γραμμής είναι ίδιο με το προηγούμενο ('$1= = prev) τότε προσθέτουμε στη λίστα το δεύτερο πεδίο(list = list " " $2) αλλιώς εκτυπώνονται τα περιεχόμενα της λίστας και ενημερώνονται οι μεταβλητές μας. Το δεύτερο πρόγραμμα απλά εκτυπώνει κατευθείαν τα διάφορα πεδία χωρίς να τα κρατάει σε κάποια λίστα και να τα εκτυπώνει γραμμή γραμμή. Χρησιμοποιήσαμε το δεύτερο πρόγραμμα για να δείξουμε μία διαφορετική σύνταξη της print, την printf που μοιάζει με αυτήν της C.


Επιστροφή