Άκρα παραδείγματα. Παραδείγματα εντολών AWK στο Linux. Μορφοποιημένη έξοδος δεδομένων

Κύριος σκοπός του προγράμματος οκ- ερμηνεία της γλώσσας προγραμματισμού awk, η οποία σας επιτρέπει να δημιουργήσετε γρήγορα ένα πρόγραμμα για την ανάλυση και τη μετατροπή αρχείων κειμένου. Ένα τυπικό σενάριο awk μοιάζει με αυτό:

template1 (action1) template2 (action2) ...

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

Εκτύπωση του τρίτου πεδίου (στήλη, λέξη) κάθε γραμμής:

Κώδικας:

ls -l | awk "(print($3))"

Εκτυπώνει τα δύο καθορισμένα πεδία κάθε γραμμής:

Κώδικας:

ls -l | awk "(print($9,$1))"

Εκτύπωση πεδίων με κενά:

Κώδικας:

ls -l | awk "(print($9," ",$1))"

Για να καθορίσετε ένα διαχωριστικό πεδίου εκτός από το διάστημα, χρησιμοποιήστε την επιλογή -F. ΣΕ σε αυτή την περίπτωσηΤο διαχωριστικό πεδίου θα είναι άνω και κάτω τελεία:

Κώδικας:

Awk -F: "(print($2))" $filenameForProcessing

Για να χρησιμοποιήσετε ένα σενάριο awk που είναι αποθηκευμένο σε ένα αρχείο:

Κώδικας:

Awk -f $scriptΌνομα αρχείου $filenameForProcessing

Το αρχείο σεναρίου awk μπορεί να γίνει εκτελέσιμο και το αντίστοιχο sha-bang να καθοριστεί σε αυτό. Ένα τέτοιο σενάριο θα λάβει ένα αρχείο για επεξεργασία ως παράμετρο:

Κώδικας:

#!/usr/bin/awk -f

Οι μεταβλητές awk δημιουργούνται την πρώτη φορά που έχουν πρόσβαση και μπορούν να περιέχουν ακέραιους αριθμούς, floats ή συμβολοσειρές, όπως καθορίζεται από το περιβάλλον. Η ειδική μεταβλητή RS αποθηκεύει την τιμή του διαχωριστή εγγραφών (\n από προεπιλογή) και η μεταβλητή FS αποθηκεύει την τιμή του διαχωριστή πεδίων (προεπιλογή - διάστημα). Εάν οποιαδήποτε από αυτές τις μεταβλητές περιέχει περισσότερους από έναν χαρακτήρες, αυτή η τιμή ερμηνεύεται ως κανονική έκφραση. Η γλώσσα awk περιέχει έναν αριθμό ενσωματωμένων συμβολοσειρών και μαθηματικές συναρτήσεις, εντολές υπό όρους και βρόχους, υποστηρίζει πίνακες και ορισμό προσαρμοσμένες λειτουργίες. Στο Διαδίκτυο μπορείτε να βρείτε εκτεταμένα εγχειρίδια για τη γλώσσα awk, καθώς και αυτόματους μεταφραστές ("μεταφραστές") σεναρίων awk σε άλλες γλώσσες (για παράδειγμα, C ή Perl).

Ειδικοί τύποι μοτίβων είναι BEGIN και END. Δεν ελέγχονται έναντι των καταχωρήσεων ροής εισόδου. Η ενέργεια μοτίβο BEGIN θα εκτελεστεί μία φορά πριν από την ανάγνωση των δεδομένων εισόδου και η ενέργεια μοτίβο END θα εκτελεστεί μία φορά μετά την ανάγνωση των δεδομένων εισόδου.

Ένα παράδειγμα κατάργησης διπλότυπων γραμμών σε ένα αρχείο:

Κώδικας:

Όνομα αρχείου=test.txt
res=`awk "BEGIN (PREV="") (if ($0 != PREV) (print $0; PREV=$0))" $filename`
echo "$res" > $όνομα αρχείου

Πριν ξεκινήσουμε, ορίζουμε τη μεταβλητή PREV στην κενή συμβολοσειρά. Το υπόλοιπο σενάριο awk δεν έχει πρότυπο και επομένως εκτελείται σε οποιαδήποτε συμβολοσειρά. Εάν η τρέχουσα γραμμή δεν είναι ίση με PREV, εκτυπώνεται και στη συνέχεια γράφεται στη μεταβλητή PREV. Έτσι, κατά την επεξεργασία κάθε γραμμής, εάν αποδειχθεί ίση με την προηγούμενη, δεν θα εκτυπωθεί.

Παράδειγμα συνένωσης πεδίου:

Κώδικας:

Awk "(a = $3 $4; print a)" $filename

Παράδειγμα άθροισης τιμών πεδίων:

Κώδικας:

Awk "(a = $3+$4; print a)" $filename

Η έννοια του "επιλογέα" θα πρέπει να κατανοηθεί ως επέκταση της έννοιας του "πρότυπο". Όπου ένα μοτίβο καθορίζεται στη δομή εντολών, στο γενική περίπτωσηΜπορεί να χρησιμοποιηθεί οποιοσδήποτε επιλογέας.

Δοκιμή του τρίτου πεδίου σε σχέση με μια τυπική έκφραση και εκτύπωση ολόκληρης της γραμμής εάν είναι επιτυχής:

Κώδικας:

Awk "$3~/(7)$/ (print)" $filename

Ελέγχει το πρώτο πεδίο για ισότητα με την καθορισμένη συμβολοσειρά και εκτυπώνει το δεύτερο πεδίο εάν είναι επιτυχές.

Μια εισαγωγή σε μια υπέροχη γλώσσα με ένα περίεργο όνομα

Daniel Robbins, Πρόεδρος/Διευθύνων Σύμβουλος, Gentoo Technologies, Inc.

Περιγραφή: Το Awk είναι μια υπέροχη γλώσσα με ένα πολύ περίεργο όνομα. Σε αυτό το πρώτο άρθρο μιας σειράς τριών μερών, ο Daniel Robbins δίνει σύντομη εισαγωγήστα βασικά του προγραμματισμού στο awk. Τα μελλοντικά άρθρα της σειράς θα καλύπτουν πιο προχωρημένα θέματα, τελειώνοντας με τη δημιουργία μιας σοβαρής εφαρμογής επίδειξης χρησιμοποιώντας το awk from πραγματική πρακτική.

Αυτό το άρθρο ετικέτες: awk

Επισημάνετε αυτό!

Ημερομηνία: 29/01/2009

Βαθμός δυσκολίας: εύκολο

Σχόλια: 0 (Προβολή | Προσθήκη σχολίου - Είσοδος)

Βαθμολογήστε αυτό το άρθρο

Στην υπεράσπιση του awk

Σε αυτή τη σειρά άρθρων, θα κάνω τον αναγνώστη έναν έμπειρο προγραμματιστή awk. Συμφωνώ ότι το awk δεν έχει το ωραιότερο ή πιο μοντέρνο όνομα και η έκδοση GNU του awk, που ονομάζεται gawk, ακούγεται εντελώς περίεργη. Προγραμματιστές που δεν είναι εξοικειωμένοι με τη γλώσσα μπορεί να ακούσουν το όνομά της και να φανταστούν ένα συνονθύλευμα αρχαίου και ξεπερασμένου κώδικα που θα μπορούσε να τρελάνει ακόμη και τον πιο έμπειρο ειδικό του UNIX (κάνοντάς τον να αναφωνεί "σκότωσε -9!" και να τρέχει συνεχώς για καφέ).

Ναι, το awk όχι υπέροχο όνομα. Αλλά είναι μια υπέροχη γλώσσα. Το Awk έχει σχεδιαστεί για επεξεργασία κειμένου και αναφορά, αλλά έχει πολλά καλά ανεπτυγμένα χαρακτηριστικά που επιτρέπουν σοβαρό προγραμματισμό. Ωστόσο, σε αντίθεση με κάποιες άλλες γλώσσες, η σύνταξη του awk είναι οικεία και δανείζεται τα καλύτερα από γλώσσες όπως η C, η python και η bash (αν και επίσημα το awk δημιουργήθηκε πριν από το python και το bash). Η Awk είναι μία από αυτές τις γλώσσες που, μόλις μαθευτεί, γίνεται βασικό μέρος του στρατηγικού οπλοστασίου ενός προγραμματιστή.

Πρώτο βήμα στο awk

Ας ξεκινήσουμε και ας δοκιμάσουμε να πειραματιστούμε με το awk για να δούμε πώς λειτουργεί. Στη γραμμή εντολών, πληκτρολογήστε την ακόλουθη εντολή: $ awk "( print )" /etc/passwd

Το αποτέλεσμα θα πρέπει να δείχνει τα περιεχόμενα του αρχείου /etc/passwd. Τώρα - μια εξήγηση του τι έκανε το awk. Όταν καλούμε το awk, ορίσαμε το /etc/passwd ως αρχείο εισόδου. Όταν τρέξαμε το awk, επεξεργαζόταν την εντολή εκτύπωσης για κάθε γραμμή στο /etc/passwd με τη σειρά. Όλη η έξοδος στάλθηκε στο stdout και πήραμε ένα αποτέλεσμα πανομοιότυπο με το αποτέλεσμα εντολές γάτας/etc/passwd. Τώρα ας εξηγήσουμε το μπλοκ ( εκτύπωση ). σε αμηχανία τιράντεςχρησιμοποιούνται για την ομαδοποίηση μπλοκ κειμένου, όπως στο C. Το μπλοκ κειμένου μας έχει μόνο μία εντολή εκτύπωσης. Στο awk η εντολή εκτύπωσης είναι χωρίς πρόσθετες παραμέτρουςεκτυπώνει όλα τα περιεχόμενα τρέχουσα γραμμή.

Ακολουθεί ένα άλλο παράδειγμα προγράμματος awk που κάνει το ίδιο πράγμα: $ awk "( print $0 )" /etc/passwd

Στο awk, η μεταβλητή $0 αντιπροσωπεύει ολόκληρη την τρέχουσα γραμμή, επομένως η εκτύπωση και η εκτύπωση $0 κάνουν ακριβώς το ίδιο πράγμα. Εάν θέλετε, μπορείτε να δημιουργήσετε ένα πρόγραμμα σε awk που θα εξάγει δεδομένα εντελώς άσχετα με τα δεδομένα εισόδου. Ακολουθεί ένα παράδειγμα: $ awk "( print "" )" /etc/passwd

Όταν περνάτε τη συμβολοσειρά "" στην εντολή εκτύπωσης, εκτυπώνει πάντα μια κενή συμβολοσειρά. Εάν δοκιμάσετε αυτό το σενάριο, θα διαπιστώσετε ότι το awk βγάζει μια κενή γραμμή για κάθε γραμμή στο /etc/passwd. Αυτό συμβαίνει ξανά επειδή το awk εκτελεί ένα σενάριο για κάθε γραμμή στο αρχείο εισόδου. Να ένα άλλο παράδειγμα: $ awk "( print "hiya" )" /etc/passwd

Εάν εκτελέσετε αυτό το σενάριο, θα γεμίσει την οθόνη με τις λέξεις "yay". :)

Πολλαπλά πεδία

Το Awk είναι κατάλληλο για την επεξεργασία κειμένου που χωρίζεται σε πολλαπλά λογικά πεδία και διευκολύνει την πρόσβαση σε κάθε μεμονωμένο πεδίο μέσα από ένα σενάριο awk. Το ακόλουθο σενάριο θα εκτυπώσει μια λίστα με όλους τους λογαριασμούς στο σύστημα: $ /etc/passwd

Στην κλήση awk στο παραπάνω παράδειγμα, η επιλογή –F καθορίζει το ":" ως διαχωριστικό πεδίου. Κατά την επεξεργασία της εντολής print $1, το awk εκτυπώνει το πρώτο πεδίο που συναντάται σε κάθε γραμμή του αρχείου εισόδου. Να ένα άλλο παράδειγμα: $ awk -F":" "( print $1 $3 )" /etc/passwd

Εδώ είναι ένα κομμάτι από την έξοδο οθόνης αυτού του σεναρίου:halt7

Όπως μπορείτε να δείτε, το awk βγάζει το πρώτο και το τρίτο πεδία του αρχείου /etc/passwd, τα οποία είναι τα πεδία ονόματος χρήστη και uid, αντίστοιχα. Ωστόσο, αν και το σενάριο λειτουργεί, δεν είναι τέλειο - δεν υπάρχουν κενά μεταξύ των δύο πεδίων εξόδου! Όσοι είναι συνηθισμένοι στον προγραμματισμό σε bash ή python ίσως περίμεναν ότι η εντολή print $1 $3 θα εισαγάγει ένα κενό μεταξύ αυτών των δύο πεδίων. Ωστόσο, όταν δύο γραμμές βρίσκονται η μία δίπλα στην άλλη σε ένα πρόγραμμα awk, το awk τις ενώνει χωρίς να προσθέτει κενό μεταξύ τους. Επόμενη εντολήθα εισαγάγει ένα κενό μεταξύ των πεδίων: $ awk -F":" "( print $1 " " $3 )" /etc/passwd

Όταν η εκτύπωση ονομάζεται με αυτόν τον τρόπο, συνενώνει $1, " " και $3 σε σειρά, παράγοντας αναγνώσιμη από τον άνθρωπο έξοδο στην οθόνη. Φυσικά, μπορούμε επίσης να εισάγουμε ετικέτες πεδίων εάν χρειάζεται: $ awk -F":" "( print "username: " $1 "\t\tuid: " $3" )" /etc/passwd

Ως αποτέλεσμα, έχουμε την ακόλουθη έξοδο: όνομα χρήστη: halt uid:7

όνομα χρήστη: operator uid:11

όνομα χρήστη: root uid:0

όνομα χρήστη: shutdown uid:6

όνομα χρήστη: sync uid:5

όνομα χρήστη: bin uid:1

Εξωτερικά σενάρια

Διαβίβαση σεναρίων στο awk ως ορίσματα γραμμή εντολώνμπορεί να είναι βολικό για μικρά κείμενα μιας γραμμής, αλλά όταν πρόκειται για πολύπλοκα προγράμματα πολλαπλών γραμμών, σίγουρα θα είναι καλύτερο να γράψετε το σενάριο ως εξωτερικό αρχείο. Στη συνέχεια, μπορείτε να δείξετε awk σε αυτό το αρχείο σεναρίου χρησιμοποιώντας την επιλογή -f:$ awk -f myscript.awk myfile.in

Η τοποθέτηση σεναρίων σε ξεχωριστά αρχεία κειμένου σάς επιτρέπει επίσης να εκμεταλλευτείτε πρόσθετα οφέληοκ. Για παράδειγμα, το ακόλουθο σενάριο πολλαπλών γραμμών κάνει το ίδιο πράγμα με ένα από τα προηγούμενα one-liners μας - εκτυπώνει το πρώτο πεδίο κάθε γραμμής από το /etc/passwd: BEGIN (

Η διαφορά μεταξύ αυτών των δύο μεθόδων είναι ο τρόπος με τον οποίο καθορίζουμε το διαχωριστικό πεδίου. Σε αυτό το σενάριο, το διαχωριστικό πεδίου καθορίζεται εσωτερικά από το ίδιο το πρόγραμμα (ρυθμίζοντας τη μεταβλητή FS), ενώ στο προηγούμενο παράδειγμά μας, το FS ρυθμίζεται περνώντας awk την επιλογή -F":" στη γραμμή εντολών. Συνήθως είναι καλύτερο να καθορίσετε το διαχωριστικό πεδίου μέσα στο ίδιο το σενάριο, απλώς και μόνο επειδή δεν θα σας ζητήσει να θυμάστε άλλο όρισμα γραμμής εντολών. Θα εξετάσουμε τη μεταβλητή FS με περισσότερες λεπτομέρειες αργότερα σε αυτό το άρθρο.

μπλοκ BEGIN και END

Συνήθως το awk εκτελεί κάθε μπλοκ στο κείμενο του σεναρίου μία φορά για κάθε γραμμή εισόδου. Ωστόσο, υπάρχουν συχνά καταστάσεις στον προγραμματισμό όπου πρέπει να εκτελέσετε τον κώδικα αρχικοποίησης πριν το awk ξεκινήσει την επεξεργασία κειμένου από ένα αρχείο εισόδου. Για τέτοιες περιπτώσεις, το awk παρέχει τη δυνατότητα ορισμού ενός μπλοκ BEGIN. Χρησιμοποιήσαμε το μπλοκ BEGIN στο προηγούμενο παράδειγμα. Επειδή το μπλοκ BEGIN υποβάλλεται σε επεξεργασία πριν το awk ξεκινήσει την επεξεργασία του αρχείου εισόδου, αυτό είναι ένα εξαιρετικό μέρος για την προετοιμασία μιας μεταβλητής FS (διαχωριστής πεδίου), την έξοδο μιας κεφαλίδας ή την προετοιμασία άλλων καθολικών μεταβλητών που θα χρησιμοποιηθούν αργότερα στο πρόγραμμα.

Το Awk παρέχει επίσης ένα άλλο ειδικό μπλοκ, που ονομάζεται μπλοκ ΤΕΛΟΣ. Το Awk εκτελεί αυτό το μπλοκ αφού ολοκληρωθεί η επεξεργασία όλων των γραμμών στο αρχείο εισόδου. Συνήθως, ένα μπλοκ ΤΕΛΟΣ χρησιμοποιείται για την εκτέλεση τελικών υπολογισμών ή αποτελεσμάτων εξόδου που θα πρέπει να εμφανίζονται στο τέλος της ροής εξόδου.

Κανονικές εκφράσεις και μπλοκ

Το Awk σάς επιτρέπει να χρησιμοποιείτε κανονικές εκφράσεις για να εκτελέσετε επιλεκτικά συγκεκριμένα μπλοκ ενός προγράμματος ανάλογα με το εάν η τυπική έκφραση ταιριάζει ή όχι με την τρέχουσα γραμμή. Ακολουθεί ένα παράδειγμα σεναρίου που εκτυπώνει μόνο εκείνες τις γραμμές που περιέχουν την ακολουθία χαρακτήρων foo:/foo/ ( print )

Φυσικά, μπορείτε να χρησιμοποιήσετε πιο σύνθετες τυπικές εκφράσεις. Ακολουθεί ένα σενάριο που θα εκτυπώνει μόνο γραμμές που περιέχουν float: /+\.*/ ( print )

Εκφράσεις και μπλοκ

Υπάρχουν πολλοί άλλοι τρόποι για να εκτελέσετε επιλεκτικά ένα μπλοκ ενός προγράμματος. Μπορούμε να τοποθετήσουμε οποιαδήποτε έκφραση Boole πριν από ένα μπλοκ προγράμματος για να ελέγξουμε την εκτέλεση αυτού του μπλοκ. Το Awk θα εκτελέσει ένα μπλοκ προγράμματος μόνο εάν η προηγούμενη Boolean έκφραση αξιολογηθεί ως true. Το ακόλουθο παράδειγμα δέσμης ενεργειών θα παράγει το τρίτο πεδίο όλων των γραμμών όπου το πρώτο πεδίο είναι fred. Εάν το πρώτο πεδίο της τρέχουσας γραμμής δεν είναι fred, το awk θα συνεχίσει να επεξεργάζεται το αρχείο και δεν θα εκδώσει δήλωση εκτύπωσης για την τρέχουσα γραμμή: :$1 == "fred" ( print $3 )

Προσφορές Awk πλήρες σεττελεστές σύγκρισης, συμπεριλαμβανομένων των συνηθισμένων "==", "<", ">", "<=", ">=" και "!=". Επιπλέον, το awk παρέχει τους τελεστές "~" και "!~", που σημαίνουν "ταιριάζει" και "δεν ταιριάζει." Τοποθετούν τη μεταβλητή στα αριστερά του τελεστή και την κανονική έκφραση στα δεξιά της Ακολουθεί ένα παράδειγμα όπου εκτυπώνεται μόνο το τρίτο πεδίο μιας γραμμής εάν το πέμπτο πεδίο της ίδιας γραμμής περιέχει τη ρίζα της ακολουθίας χαρακτήρων:$5 ~ /root/ ( εκτύπωση $3 )

Δηλώσεις υπό όρους

Το Awk παρέχει επίσης πολύ ωραίες δηλώσεις τύπου C if. Εάν θέλετε, μπορείτε να ξαναγράψετε προηγούμενο σενάριοχρησιμοποιώντας εάν:(

αν ($5 ~ /root/) (

Και τα δύο σενάρια λειτουργούν πανομοιότυπα. Στο πρώτο παράδειγμα, η δυαδική έκφραση είναι έξω από το μπλοκ, ενώ στο δεύτερο παράδειγμα, το μπλοκ εκτελείται για κάθε γραμμή εισόδου και εκτελούμε επιλεκτικά την εντολή εκτύπωσης χρησιμοποιώντας την εντολή if και οι δύο μέθοδοι λειτουργούν και μπορούμε να επιλέξουμε τη μία ότι με τον καλύτερο δυνατό τρόποσυγχωνεύεται με άλλα μέρη του σεναρίου.

Εδώ είναι περισσότερα σύνθετο παράδειγμααν δήλωση σε awk. Όπως μπορείτε να δείτε, ακόμη και στην περίπτωση σύνθετων ένθετων υπό όρουςεάν οι δηλώσεις μοιάζουν πανομοιότυπες με τις αντίστοιχες C:(

αν ($1 == "foo") (

αν ($2 == "foo") (

) αλλιώς εάν ($1 == "bar") (

Χρησιμοποιώντας τις εντολές if, μπορούμε να μετατρέψουμε αυτόν τον κώδικα: ! /matchme/ (εκτύπωση $1 $3 $4)

κάπως έτσι: (

αν ($0 !~ /matchme/) (

Και τα δύο σενάρια θα εκτυπώσουν μόνο γραμμές που δεν περιέχουν την ακολουθία χαρακτήρων matchme. Και σε αυτή την περίπτωση, επίσης, μπορείτε να επιλέξετε μια μέθοδο που λειτουργεί καλύτερα συγκεκριμένο πρόγραμμα. Και οι δύο κάνουν το ίδιο πράγμα.

Το Awk σας επιτρέπει επίσης να χρησιμοποιήσετε Boolean τελεστές"||" ("λογικό Ή") και "&&" ("λογικό ΚΑΙ"), που σας επιτρέπει να δημιουργήσετε πιο σύνθετες εκφράσεις Boole: ($1 == "foo") && ($2 == "bar") ( εκτύπωση )

Αυτό το παράδειγμα θα παράγει μόνο σειρές όπου το πρώτο πεδίο είναι foo και το δεύτερο πεδίο είναι η γραμμή.

Αριθμητικές μεταβλητές!

Μέχρι στιγμής έχουμε εκτυπώσει είτε μεταβλητές συμβολοσειρών, ολόκληρες συμβολοσειρές ή συγκεκριμένα πεδία. Ωστόσο, το awk μας δίνει επίσης τη δυνατότητα να κάνουμε συγκρίσεις τόσο σε ακέραιους όσο και σε αριθμούς κινητής υποδιαστολής. Χρησιμοποιώντας μαθηματικές εκφράσεις, είναι πολύ εύκολο να γράψετε ένα σενάριο που μετράει έναν αριθμό κενές γραμμέςστο αρχείο. Εδώ είναι ένα τέτοιο σενάριο: BEGIN ( x=0 )

ΤΕΛΟΣ ( εκτύπωση "Βρέθηκαν " x " κενές γραμμές. :)"

Στο μπλοκ BEGIN, αρχικοποιούμε την ακέραια μεταβλητή x στο μηδέν. Στη συνέχεια, κάθε φορά που το awk συναντά μια κενή γραμμή, θα εκτελεί την πρόταση x=x+1, αυξάνοντας το x κατά 1. Μόλις ολοκληρωθεί η επεξεργασία όλων των γραμμών, το μπλοκ ΤΕΛΟΣ θα εκτελεστεί και το awk θα εκτυπώνει το τελικό σύνολο, υποδεικνύοντας τον αριθμό των κενών γραμμών που βρέθηκαν.

Μεταβλητές συμβολοσειράς

Ένα από τα ωραία πράγματα με τις μεταβλητές awk είναι ότι είναι "απλές και πεζά". Ονομάζω τις μεταβλητές awk "string" επειδή όλες οι μεταβλητές awk αποθηκεύονται εσωτερικά ως συμβολοσειρές. Ταυτόχρονα, οι μεταβλητές awk είναι "απλές" επειδή μπορείτε να εκτελέσετε μαθηματικές πράξεις στη μεταβλητή και εάν περιέχει τη σωστή αριθμητική γραμμή, το awk θα φροντίσει αυτόματα να μετατρέψει τη συμβολοσειρά σε αριθμό. Για να καταλάβετε τι εννοώ, ρίξτε μια ματιά σε αυτό το παράδειγμα: x="1.01"

# Κάναμε το x να περιέχει το *string* "1.01"

# Μόλις προσθέσαμε 1 στο *string*

# Αυτό είναι ένα σχόλιο, παρεμπιπτόντως :)

Το Awk θα βγει: 2.01

Περίεργος! Αν και εκχωρήσαμε την τιμή συμβολοσειράς 1,01 στο x, μπορέσαμε να προσθέσουμε μία σε αυτήν. Δεν μπορούσαμε να το κάνουμε αυτό σε bash ή python. Πρώτα απ 'όλα, το bash δεν υποστηρίζει αριθμητική κινητής υποδιαστολής. Και ενώ το bash έχει μεταβλητές "string", δεν είναι "απλές". να πραγματοποιήσει οποιαδήποτε μαθηματικές πράξειςΤο bash απαιτεί να τυλίξουμε τους υπολογισμούς μας σε άσχημες κατασκευές $(). Εάν χρησιμοποιούσαμε python, θα έπρεπε να μετατρέψουμε ρητά τη συμβολοσειρά μας 1.01 σε τιμή κινητής υποδιαστολής πριν κάνουμε οποιουσδήποτε υπολογισμούς με αυτήν. Αν και δεν είναι δύσκολο, είναι ακόμα επιπλέον βήμα. Στην περίπτωση του awk, όλα αυτά γίνονται αυτόματα, και κάνει τον κώδικα μας ωραίο και καθαρό. Αν χρειαζόταν να τετραγωνίσουμε το πρώτο πεδίο κάθε συμβολοσειράς εισόδου και να προσθέσουμε ένα σε αυτό, θα χρησιμοποιούσαμε ένα σενάριο όπως αυτό:( print ($1^2)+1 )

Αν πειραματιστείτε λίγο, θα διαπιστώσετε ότι αν μια μεταβλητή δεν περιέχει τον σωστό αριθμό, θα υπολογιστεί το awk μαθηματική έκφρασηθα αντιμετωπίσει αυτή τη μεταβλητή ως αριθμητικό μηδέν.

Πολλοί χειριστές

Ένα ακόμα ωραίο χαρακτηριστικό awk είναι πλήρες σετμαθηματικούς τελεστές. Εκτός από την τυπική πρόσθεση, αφαίρεση, πολλαπλασιασμό και διαίρεση, το awk μας δίνει τη δυνατότητα να χρησιμοποιήσουμε τον προηγουμένως αποδεδειγμένο τελεστή εκθέτη "^", τον τελεστή υπολοίπου διαίρεσης ακέραιου αριθμού "%" και πολλούς άλλους βολικούς τελεστές εκχώρησης δανεισμένους από το C.

Αυτοί περιλαμβάνουν τελεστές εκχώρησης πριν και μετά την αύξηση/φθίνουσα ανάθεση (i++, --foo), τους τελεστές ανάθεσης με πρόσθεση/αφαίρεση/πολλαπλασιασμό/διαίρεση (a+=3, b*=2, c/=2,2, d-=6,2) . Αλλά αυτό δεν είναι μόνο - έχουμε επίσης βολικούς τελεστές εκχώρησης με υπολογισμό του υπολοίπου της διαίρεσης και της εκθέσεως (a^=2, b%=4).

Διαχωριστές πεδίου

Το awk έχει το δικό του σύνολο ειδικών μεταβλητών. Κάποια από αυτά το κάνουν δυνατό λεπτό συντονισμό awk λειτουργεί, και άλλα περιέχουν πολύτιμες πληροφορίεςσχετικά με την εισαγωγή. Έχουμε ήδη αγγίξει μια από αυτές τις ειδικές μεταβλητές, την FS. Όπως αναφέρθηκε προηγουμένως, αυτή η μεταβλητή σάς επιτρέπει να καθορίσετε την ακολουθία χαρακτήρων που το awk θα θεωρήσει ως διαχωριστικό πεδίου. Όταν χρησιμοποιήσαμε το /etc/passwd ως είσοδο, το FS ορίστηκε σε ":". Αυτό αποδείχθηκε αρκετό, αλλά το FS μας δίνει ακόμα μεγαλύτερη ευελιξία.

Η τιμή της μεταβλητής FS δεν χρειάζεται να είναι ένας μόνο χαρακτήρας. μπορεί να της εκχωρηθεί μια τυπική έκφραση που καθορίζει ένα μοτίβο χαρακτήρων οποιουδήποτε μήκους. Εάν επεξεργάζεστε πεδία που χωρίζονται από έναν ή περισσότερους χαρακτήρες καρτέλας, τότε το FS πρέπει να ρυθμιστεί ως εξής: FS="\t+"

Παραπάνω χρησιμοποιήσαμε ιδιαίτερο χαρακτήρακανονική έκφραση "+" που σημαίνει "μία ή περισσότερες εμφανίσεις του προηγούμενου χαρακτήρα".

Εάν τα πεδία διαχωρίζονται με λευκό διάστημα (ένα ή περισσότερα κενά ή καρτέλες), μπορεί να θέλετε να ορίσετε το FS στην ακόλουθη τυπική έκφραση:FS="[[:space:]+]"

Αν και αυτή η ρύθμιση θα λειτουργήσει, δεν είναι απαραίτητη. Γιατί; Επειδή η προεπιλεγμένη τιμή του FS είναι ένας χαρακτήρας διαστήματος, ο οποίος ερμηνεύει το awk ως "ένα ή περισσότερα κενά ή καρτέλες". Στο δικό μας συγκεκριμένο παράδειγμαΗ προεπιλεγμένη τιμή FS είναι ακριβώς αυτό που χρειαζόμασταν!

Δεν υπάρχουν επίσης προβλήματα με σύνθετες κανονικές εκφράσεις. Ακόμα κι αν οι εγγραφές διαχωρίζονται από τη λέξη "foo" ακολουθούμενη από τρία ψηφία, η ακόλουθη τυπική έκφραση θα αναλύσει σωστά τα δεδομένα: FS="foo"

Αριθμός πεδίων

Οι επόμενες δύο μεταβλητές που θα εξετάσουμε συνήθως δεν προορίζονται για εγγραφή, αλλά χρησιμοποιούνται για ανάγνωση και λήψη χρήσιμες πληροφορίεςσχετικά με την εισαγωγή. Η πρώτη από αυτές είναι η μεταβλητή NF, που ονομάζεται επίσης αριθμός πεδίων. Το Awk ορίζει αυτόματα την τιμή αυτής της μεταβλητής ίσο με τον αριθμόπεδία στην τρέχουσα εγγραφή. Μπορείτε να χρησιμοποιήσετε τη μεταβλητή NF για να εμφανίσετε μόνο ορισμένες γραμμές εισόδου: NF == 3 (εκτύπωση "υπάρχουν τρία πεδία σε αυτήν την καταχώρηση: " $0 )

Φυσικά, η μεταβλητή NF μπορεί επίσης να χρησιμοποιηθεί σε δηλώσεις υπό όρους, για παράδειγμα:(

αν (NF > 2) (

εκτύπωση $1 " " $2 ":" $3

Αριθμός αρχείου

Μια άλλη βολική μεταβλητή είναι ο αριθμός εγγραφής (NR). Περιέχει πάντα τον αριθμό της τρέχουσας εγγραφής (το awk θεωρεί ότι η πρώτη εγγραφή είναι ο αριθμός εγγραφής 1). Μέχρι στιγμής έχουμε να κάνουμε με αρχεία εισόδου που περιέχουν μία εγγραφή ανά γραμμή. Σε τέτοιες περιπτώσεις, η NR θα αναφέρει επίσης τον τρέχοντα αριθμό γραμμής. Ωστόσο, όταν αρχίσουμε να χειριζόμαστε εγγραφές πολλαπλών γραμμών σε μεταγενέστερα άρθρα αυτής της σειράς, αυτό δεν θα ισχύει πλέον, επομένως πρέπει να είστε προσεκτικοί! Το NR μπορεί να χρησιμοποιηθεί όπως η μεταβλητή NF για την έξοδο μόνο συγκεκριμένων γραμμών εισόδου: (NR< 10) || (NR >100) ( εκτύπωση "Βρισκόμαστε στον αριθμό ρεκόρ 1-9 ή 101 ή περισσότερο")

Άλλο παράδειγμα:(

αν (NR > 10) (

print "τώρα έρχονται οι πραγματικές πληροφορίες!"

Το Awk παρέχει πρόσθετες μεταβλητές που μπορούν να χρησιμοποιηθούν για διάφορους σκοπούς. Θα εξετάσουμε αυτές τις μεταβλητές σε μελλοντικά άρθρα. Φτάσαμε στο τέλος της αρχικής μας εξερεύνησης του awk. Σε μελλοντικά άρθρα της σειράς, θα δείξω πιο προηγμένες λειτουργίες awk και θα ολοκληρώσουμε αυτήν τη σειρά με μια εφαρμογή awk πραγματικού κόσμου. Εν τω μεταξύ, εάν θέλετε να μάθετε περισσότερα, μπορείτε να ελέγξετε τους πόρους που αναφέρονται παρακάτω.

04.10.2015
16:55

Το βοηθητικό πρόγραμμα awk είναι ένα παράδειγμα κλασικού εφαρμογές Linuxγια επεξεργασία κειμένου. Είναι πολύ ευέλικτο και αποτελεσματικό, αν και δεν παρέχει μια πλήρη γλώσσα προγραμματισμού. Ωστόσο, να είστε σίγουροι ότι οι δυνατότητές του είναι αρκετά επαρκείς για την επίλυση πολλών προβλημάτων. αυτοματοποιημένη επεξεργασίακείμενο (ειδικά όταν συνδυάζεται με άλλα βοηθητικά προγράμματα κονσόλας).

Τρόποι εκτέλεσης προγραμμάτων awk

Εάν το πρόγραμμα awk είναι αρκετά απλό και σύντομο, τότε ο κώδικάς του μπορεί να πληκτρολογηθεί απευθείας στην κονσόλα:

οκ"< код awk-программы >" < имя_файла_для_обработки >

Μπορείτε να χρησιμοποιήσετε περισσότερα από το awk ως είσοδο: αρχεία κειμένου, αλλά και την έξοδο μέσα τυπική ροήάλλες εφαρμογές:

< некое_приложение >| οκ"< код awk-программы >"

Στην περίπτωση που ο κώδικας του προγράμματος awk είναι αρκετά μεγάλος ή πρέπει να αποθηκευτεί επαναχρησιμοποίηση, μπορεί να κληθεί από ένα αρχείο με το διακόπτη -f:

Awk -f< имя_файла_с_кодом_awk_программы > < имя_файла_для_обработки >

Για να πραγματοποιήσουμε πειράματα, χρησιμοποιούμε το αρχείο test.cpp, στο οποίο θα ελέγξουμε τα αποτελέσματα των προγραμμάτων awk:

#συμπεριλαμβάνω #συμπεριλαμβάνω #συμπεριλαμβάνω void test1(); int test2(); // Σχόλιο στυλ C για τη συνάρτηση main() int main(int argc, char** argv) ( std::cout<< "Hello, world!" << std::endl; for(int i = 0; i < 10; ++i) { std::cout << i << std::endl; } return 0; } // Комментарий в стиле С для функции test1() void test1() { std::cout << "Hello, test1!" << std::endl; } // Комментарий в стиле С для функции test2() int test2() { std::cout << "Hello, test2!" << std::endl; }

Διαφήμιση

Φιλτράρισμα χορδών με χρήση awk

Πρώτα απ 'όλα, το awk σάς επιτρέπει να επιλέξετε γραμμές από κείμενο με βάση κανονικές εκφράσεις και ορισμένες αριθμητικές συνθήκες.

Επιλογή συμβολοσειρών που ταιριάζουν με μια κανονική έκφραση

Για παράδειγμα, για να λάβουμε όλες τις γραμμές στο αρχείο test.cpp που περιέχουν την οδηγία προεπεξεργαστή #include, χρησιμοποιούμε την ακόλουθη εντολή:

Awk "/^#\s*include/" test.cpp

Η τυπική έκφραση γράφεται μεταξύ δύο / χαρακτήρων. Ως αποτέλεσμα παίρνουμε:

#συμπεριλαμβάνω #συμπεριλαμβάνω #συμπεριλαμβάνω

Επιλογή συμβολοσειρών που ΔΕΝ ταιριάζουν με κανονική έκφραση

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

Awk "! /^[/](2).*/" test.cpp

Να τι μένει:

#συμπεριλαμβάνω #συμπεριλαμβάνω #συμπεριλαμβάνω void test1(); int test2(); int main(int argc, char** argv) ( std::cout<< "Hello, world!" << std::endl; for(int i = 0; i < 10; ++i) { std::cout << i << std::endl; } return 0; } void test1() { std::cout << "Hello, test1!" << std::endl; } int test2() { std::cout << "Hello, test2!" << std::endl; }

Επιλογή σειρών από μια δεδομένη περιοχή

Μπορείτε να ορίσετε ένα εύρος συμβολοσειρών που θα εμφανίζονται στην οθόνη χρησιμοποιώντας δύο κανονικές εκφράσεις, διαχωρισμένες με κόμματα. Για παράδειγμα, ας βρούμε τον ορισμό όλων των συναρτήσεων που επιστρέφουν int:

Awk "/^int .*(.*) (/, /^)/" test.cpp

Σχετικό αποτέλεσμα:

Int main(int argc, char** argv) ( std::cout<< "Hello, world!" << std::endl; for(int i = 0; i < 10; ++i) { std::cout << i << std::endl; } return 0; } int test2() { std::cout << "Hello, test2!" << std::endl; }

Συνδυασμός συνθηκών φίλτρου

Για να ελέγξετε τις συμβολοσειρές έναντι πολλών συνθηκών ταυτόχρονα, χρησιμοποιήστε τους τελεστές && (AND) και ||. (Ή) .

Η ακόλουθη εντολή εκτυπώνει όλα τα σχόλια που δεν περιέχουν main:

Awk "/[/](2).*/ && ! /main/" test.cpp

Ως αποτέλεσμα έχουμε:

// Σχόλιο σε στυλ C για τη συνάρτηση test1() // Σχόλιο σε στυλ C για τη συνάρτηση test2().

Προηγουμένως, αναζητούσαμε μια σειρά γραμμών χρησιμοποιώντας δύο κανονικές εκφράσεις, αλλά εάν οι αριθμοί γραμμών που πρέπει να εξαχθούν είναι γνωστοί εκ των προτέρων, τότε όλα απλοποιούνται:

Awk "4< NR && NR < 7" test.cpp

Το NR είναι μια μεταβλητή awk που καθορίζει τον αριθμό γραμμής. Έτσι, ο παρουσιαζόμενος κώδικας βγάζει την 5η και 6η γραμμή:

Κενό test1(); int test2();

Επιλογή γραμμών με βάση τις συνθήκες που αφορούν μεμονωμένες λέξεις

Το Awk μπορεί να φιλτράρει το κείμενο όχι μόνο κατά γραμμές, αλλά και με μεμονωμένες λέξεις. Η i -η λέξη σε μια γραμμή μπορεί να αναφέρεται χρησιμοποιώντας $i . Η αρίθμηση ξεκινά από ένα και το $0 ορίζει τα περιεχόμενα ολόκληρης της γραμμής. Ο αριθμός των λέξεων σε μια γραμμή καθορίζεται χρησιμοποιώντας τη μεταβλητή NF, επομένως το $NF δείχνει την τελευταία λέξη. Για παράδειγμα, ας βρούμε γραμμές των οποίων η πρώτη λέξη είναι int ή void:

Awk "$1 == "int" || $1 == "void"" test.cpp

Αντίστοιχη έξοδος κονσόλας:

Κενό test1(); int test2(); int main(int argc, char** argv) ( void test1() ( int test2() (

Ωστόσο, είναι ευκολότερο να χρησιμοποιήσετε έναν έλεγχο κανονικής έκφρασης έναντι μιας λέξης. Για να γίνει αυτό, το awk παρέχει έναν ειδικό τελεστή ~, ο οποίος πρέπει να τοποθετηθεί μεταξύ της μεταβλητής που δείχνει τη λέξη και της κανονικής έκφρασης. Για παράδειγμα, ας ξαναγράψουμε την προηγούμενη εντολή σε πιο συμπαγή μορφή:

Awk "$1 ~ /int|void/" test.cpp

Επιλέξτε σειρές με βάση αριθμητικά χαρακτηριστικά

Οι αριθμητικοί τελεστές της γλώσσας C είναι διαθέσιμοι στο awk, γεγονός που σας δίνει ελευθερία δράσης. Το παρακάτω παράδειγμα εκτυπώνει όλες τις ζυγές γραμμές (το NR είναι ο αριθμός γραμμής):

Awk "NR % 2 == 0" test.cpp

Σχετική έξοδος:

#συμπεριλαμβάνω int test2(); // Σχόλιο στυλ C για τη συνάρτηση main() std::cout<< "Hello, world!" << std::endl; for(int i = 0; i < 10; ++i) { } return 0; void test1() { } // Комментарий в стиле С для функции test2() std::cout << "Hello, test2!" << std::endl;

Το ακόλουθο πρόγραμμα awk εκτυπώνει όλες τις γραμμές των οποίων η 1η λέξη έχει μήκος τρεις:

Awk "length($1) == 3" test.cpp

Ως αποτέλεσμα παίρνουμε:

Int test2(); int main(int argc, char** argv) ( int test2() (

Awk "NF == 2" test.cpp

Και η αντίστοιχη έξοδος:

#συμπεριλαμβάνω #συμπεριλαμβάνω #συμπεριλαμβάνω void test1(); int test2();

Διαφήμιση

επιστροφή 0;

Εργασία με χορδές σε awk

Όπως μπορείτε να δείτε, το awk έχει ένα καλό σύνολο λειτουργιών για το φιλτράρισμα συμβολοσειρών κειμένου. Ωστόσο, μπορείτε ακόμα να εκτελέσετε διάφορους μετασχηματισμούς σε αυτές τις χορδές. Οι εντολές συμβολοσειράς πρέπει να είναι τυλιγμένες σε σγουρά άγκιστρα (...). Ο κώδικας σε παρένθεση καλείται διαδοχικά για κάθε γραμμή κειμένου που υποβάλλεται σε επεξεργασία.

Μορφοποιημένη έξοδος

Το Awk έχει ένα άμεσο ισοδύναμο με τη συνάρτηση printf() της γλώσσας C. Για παράδειγμα, ας τυπώσουμε τον αριθμό του στην αρχή κάθε γραμμής:

Awk "( printf "%-2d %s\n", NR, $0 )" test.cpp

Να τι πήραμε: 1 #περιλαμβάνει 2 #περιλαμβάνουν 3 #περιλαμβάνουν<< "Hello, world!" << std::endl; 11 12 for(int i = 0; i < 10; ++i) { 13 std::cout << i << std::endl; 14 } 15 16 return 0; 17 } 18 19 // Комментарий в стиле С для функции test1() 20 void test1() { 21 std::cout << "Hello, test1!" << std::endl; 22 } 23 24 // Комментарий в стиле С для функции test2() 25 int test2() { 26 std::cout << "Hello, test2!" << std::endl; 27 }

4 5 void test1(); 6 int test2(); 7 8 // Σχόλιο σε στυλ C για τη συνάρτηση main() 9 int main(int argc, char** argv) ( 10 std::cout

Λειτουργίες μετατροπής

Εκτός από το printf(), το awk έχει και άλλες λειτουργίες. Για παράδειγμα, print() και toupper():

Σχετικό αποτέλεσμα:

Awk "( print toupper($0) )" test.cpp #ΣΥΜΠΕΡΙΛΑΜΒΑΝΩ #ΣΥΜΠΕΡΙΛΑΜΒΑΝΩ #ΣΥΜΠΕΡΙΛΑΜΒΑΝΩ<< "HELLO, WORLD!" << STD::ENDL; FOR(INT I = 0; I < 10; ++I) { STD::COUT << I << STD::ENDL; } RETURN 0; } // КОММЕНТАРИЙ В СТИЛЕ С ДЛЯ ФУНКЦИИ TEST1() VOID TEST1() { STD::COUT << "HELLO, TEST1!" << STD::ENDL; } // КОММЕНТАРИЙ В СТИЛЕ С ДЛЯ ФУНКЦИИ TEST2() INT TEST2() { STD::COUT << "HELLO, TEST2!" << STD::ENDL; }

VOID TEST1(); INT TEST2(); // ΣΧΟΛΙΟ C-STYLE FOR MAIN() FUNCTION INT MAIN(INT ARGC, CHAR** ARGV) ( STD::COUT

Προϋποθέσεις

Οι δηλώσεις If-else είναι διαθέσιμες σε προγράμματα awk. Για παράδειγμα, ο παρακάτω κώδικας εκτυπώνεται χωρίς να αλλάζει γραμμές που έχουν int στην 1η θέση και ( στην τελευταία, διαφορετικά --- αποστέλλεται στην κονσόλα:

Awk " ( if($1 == "int" && $NF == "() print; else print "---" )" test.cpp

Η εκτέλεση του κώδικα παράγει την ακόλουθη έξοδο:

Int main(int argc, char** argv) ( --- --- --- --- --- --- --- --- --- --- --- --- --- - --- --- int test2() ( --- ---

Μεταβλητές

Οι μεταβλητές που δεν χρειάζεται να δηλωθούν πρώτα είναι επίσης διαθέσιμες στα προγράμματα awk. Ο παρακάτω κώδικας για την καταμέτρηση του αριθμού των γραμμών και των λέξεων στο κείμενο θα τοποθετηθεί στο αρχείο stat.awk:

( lineCount++; wordCount += NF ) END ( printf "αριθμός γραμμών: %d, αριθμός λέξεων: %d\n", lineCount, wordCount )

Τότε ονομάζεται ως εξής:

Awk -f stat.awk test.cpp

Αποτέλεσμα εκτέλεσης:

Το φίλτρο ΤΕΛΟΣ καθορίζει ότι ο κώδικας σε παρένθεση μετά από αυτό θα πρέπει να εκτελείται μόνο αφού έχουν διασχιστεί όλες οι γραμμές. Το φίλτρο BEGIN είναι επίσης διαθέσιμο σε awk, οπότε σε μια γενικότερη περίπτωση το πρόγραμμα έχει τη μορφή:

BEGIN (Καλείται πριν από την έναρξη της διέλευσης σειράς) (Καλείται για κάθε σειρά μετά την ενότητα BEGIN, αλλά πριν από την ενότητα ΤΕΛΟΣ) END (Καλείται μετά την ολοκλήρωση της διέλευσης σειράς)

Wc -lw test.cpp

Κύκλοι

Στα προγράμματα awk, έχετε επίσης πρόσβαση σε βρόχους τύπου C για και ενώ. Για παράδειγμα, ας εκτυπώσουμε όλες τις γραμμές με αντίστροφη σειρά. Ας δημιουργήσουμε ένα αρχείο reverse.awk με τα ακόλουθα περιεχόμενα:

( for(i = NF; i > 0; --i) printf "%s ", $i; printf "\n" )

Ας ονομάσουμε το πρόγραμμα ως εξής:

Awk -f reverse.awk test.cpp

Ως αποτέλεσμα, οι λέξεις σε κάθε γραμμή θα εκτυπωθούν με αντίστροφη σειρά:

#συμπεριλαμβάνω #συμπεριλαμβάνω #include test1(); void test2(); συναρτήσεις int main() για στυλ C στο Comment // () argv char** argc, int main(int std::endl;<< world!" "Hello, << std::cout {) ++i 10; < i 0; = i int for(std::endl; << i << std::cout } 0; return } test1() функции для С стиле в Комментарий // { test1() void std::endl; << test1!" "Hello, << std::cout } test2() функции для С стиле в Комментарий // { test2() int std::endl; << test2!" "Hello, << std::cout }

Μη τυπικό διαχωριστικό λέξεων

Από προεπιλογή, το awk χρησιμοποιεί χαρακτήρες κενού διαστήματος ως διαχωριστικά λέξεων, αλλά αυτή η συμπεριφορά μπορεί να αλλάξει. Για να το κάνετε αυτό, χρησιμοποιήστε το διακόπτη -F, ακολουθούμενο από μια γραμμή που ορίζει το διαχωριστικό. Για παράδειγμα, το παρακάτω πρόγραμμα εμφανίζει το όνομα μιας ομάδας και των χρηστών της (αν υπάρχουν χρήστες στην ομάδα) από το αρχείο /etc/group, χρησιμοποιώντας τον χαρακτήρα άνω και κάτω τελείας ως οριοθέτη:

Awk -F":" "( if($4) printf "%15s: %s\n", $1, $4 )" /etc/group

Συνδυασμός φίλτρων και εντολών εκτύπωσης

Όλα τα φίλτρα που συζητήθηκαν προηγουμένως μπορούν να χρησιμοποιηθούν σε συνδυασμό με εντολές επεξεργασίας συμβολοσειρών. Αρκεί να γράψετε τους περιορισμούς πριν από τα σγουρά σιδεράκια. Ακολουθεί ένα παράδειγμα για την εκτύπωση των πρώτων 9 γραμμών της εξόδου της εντολής ps, που περιέχει πληροφορίες σχετικά με τον χρήστη, το αναγνωριστικό διαδικασίας και το όνομα εντολής:

Ps axu | awk "NR< 10 { print $1, $2, $NF }"

Μετά την εκκίνηση θα δούμε:

USER PID ΕΝΤΟΛΗ ρίζα 1 /sbin/init root 2 root 3 root 5 root 7 root 8 root 9 root 10

Μια εισαγωγή σε μια υπέροχη γλώσσα με ένα περίεργο όνομα

Σειρά περιεχομένου:

Στην υπεράσπιση του awk

Σε αυτή τη σειρά άρθρων, θα κάνω τον αναγνώστη έναν έμπειρο προγραμματιστή awk. Συμφωνώ ότι το awk δεν έχει το ωραιότερο ή πιο μοντέρνο όνομα και η έκδοση GNU του awk, που ονομάζεται gawk, ακούγεται εντελώς περίεργη. Προγραμματιστές που δεν είναι εξοικειωμένοι με τη γλώσσα μπορεί να ακούσουν το όνομά της και να φανταστούν ένα συνονθύλευμα αρχαίου και ξεπερασμένου κώδικα που θα μπορούσε να τρελάνει ακόμη και τον πιο έμπειρο ειδικό του UNIX (κάνοντάς τον να αναφωνεί "σκότωσε -9!" και να τρέχει συνεχώς για καφέ).

Ναι, το awk δεν έχει σπουδαίο όνομα. Αλλά είναι μια υπέροχη γλώσσα. Το Awk έχει σχεδιαστεί για επεξεργασία κειμένου και αναφορά, αλλά έχει πολλά καλά ανεπτυγμένα χαρακτηριστικά που επιτρέπουν σοβαρό προγραμματισμό. Ωστόσο, σε αντίθεση με κάποιες άλλες γλώσσες, η σύνταξη του awk είναι οικεία και δανείζεται τα καλύτερα από γλώσσες όπως η C, η python και η bash (αν και επίσημα το awk δημιουργήθηκε πριν από το python και το bash). Η Awk είναι μία από αυτές τις γλώσσες που, μόλις μαθευτεί, γίνεται βασικό μέρος του στρατηγικού οπλοστασίου ενός προγραμματιστή.

Πρώτο βήμα στο awk

Ας ξεκινήσουμε και ας δοκιμάσουμε να πειραματιστούμε με το awk για να δούμε πώς λειτουργεί. Στη γραμμή εντολών, πληκτρολογήστε την ακόλουθη εντολή:

$awk "( print )" /etc/passwd

Το αποτέλεσμα θα πρέπει να δείχνει τα περιεχόμενα του αρχείου /etc/passwd. Τώρα - μια εξήγηση του τι έκανε το awk. Όταν καλούμε το awk, ορίσαμε το /etc/passwd ως αρχείο εισόδου. Όταν τρέξαμε το awk, επεξεργαζόταν την εντολή εκτύπωσης για κάθε γραμμή στο /etc/passwd με τη σειρά. Όλη η έξοδος αποστέλλεται στο stdout και έχουμε το ίδιο αποτέλεσμα με το cat /etc/passwd. Τώρα ας εξηγήσουμε το μπλοκ (εκτύπωση). Στο awk, τα σγουρά άγκιστρα χρησιμοποιούνται για την ομαδοποίηση μπλοκ κειμένου, όπως ακριβώς στο C. Στο μπλοκ κειμένου μας, υπάρχει μόνο μία εντολή εκτύπωσης. Στο awk, η εντολή εκτύπωσης χωρίς πρόσθετες παραμέτρους εκτυπώνει ολόκληρο το περιεχόμενο της τρέχουσας γραμμής.

Ακολουθεί ένα άλλο παράδειγμα ενός προγράμματος awk που κάνει το ίδιο πράγμα:

$awk "( print $0 )" /etc/passwd

Στο awk, η μεταβλητή $0 αντιπροσωπεύει ολόκληρη την τρέχουσα γραμμή, επομένως η εκτύπωση και η εκτύπωση $0 κάνουν ακριβώς το ίδιο πράγμα. Εάν θέλετε, μπορείτε να δημιουργήσετε ένα πρόγραμμα σε awk που θα εξάγει δεδομένα εντελώς άσχετα με τα δεδομένα εισόδου. Εδώ είναι ένα παράδειγμα:

$awk "( εκτύπωση "" )" /etc/passwd

Όταν περνάτε τη συμβολοσειρά "" στην εντολή εκτύπωσης, εκτυπώνει πάντα μια κενή συμβολοσειρά. Εάν δοκιμάσετε αυτό το σενάριο, θα διαπιστώσετε ότι το awk βγάζει μια κενή γραμμή για κάθε γραμμή στο /etc/passwd. Αυτό συμβαίνει ξανά επειδή το awk εκτελεί ένα σενάριο για κάθε γραμμή στο αρχείο εισόδου. Εδώ είναι ένα άλλο παράδειγμα:

$awk "( εκτύπωση "hiya" )" /etc/passwd

Εάν εκτελέσετε αυτό το σενάριο, θα γεμίσει την οθόνη με τις λέξεις "yay". :)

Πολλαπλά πεδία

Το Awk είναι κατάλληλο για την επεξεργασία κειμένου που χωρίζεται σε πολλαπλά λογικά πεδία και διευκολύνει την πρόσβαση σε κάθε μεμονωμένο πεδίο μέσα από ένα σενάριο awk. Το ακόλουθο σενάριο θα εκτυπώσει μια λίστα με όλους τους λογαριασμούς στο σύστημα:

$ awk -F":" "( εκτύπωση $1 )" /etc/passwd

Στην κλήση awk στο παραπάνω παράδειγμα, η επιλογή –F καθορίζει το ":" ως διαχωριστικό πεδίου. Κατά την επεξεργασία της εντολής print $1, το awk εκτυπώνει το πρώτο πεδίο που συναντάται σε κάθε γραμμή του αρχείου εισόδου. Εδώ είναι ένα άλλο παράδειγμα:

$ awk -F":" "( εκτύπωση $1 $3 )" /etc/passwd

Ακολουθεί ένα απόσπασμα από την έξοδο οθόνης αυτού του σεναρίου:

halt7 operator11 root0 shutdown6 sync5 bin1 ....κ.λπ.

Όπως μπορείτε να δείτε, το awk βγάζει το πρώτο και το τρίτο πεδία του αρχείου /etc/passwd, τα οποία είναι τα πεδία ονόματος χρήστη και uid, αντίστοιχα. Ωστόσο, αν και το σενάριο λειτουργεί, δεν είναι τέλειο - δεν υπάρχουν κενά μεταξύ των δύο πεδίων εξόδου! Όσοι είναι συνηθισμένοι στον προγραμματισμό σε bash ή python ίσως περίμεναν ότι η εντολή print $1 $3 θα εισαγάγει ένα κενό μεταξύ αυτών των δύο πεδίων. Ωστόσο, όταν δύο γραμμές βρίσκονται η μία δίπλα στην άλλη σε ένα πρόγραμμα awk, το awk τις ενώνει χωρίς να προσθέτει κενό μεταξύ τους. Η ακόλουθη εντολή θα εισάγει ένα κενό μεταξύ των πεδίων:

$ awk -F":" "( εκτύπωση $1 " " $3 )" /etc/passwd

Όταν η εκτύπωση ονομάζεται με αυτόν τον τρόπο, συνενώνει $1 , " " και $3 σε σειρά, παράγοντας αναγνώσιμο από τον άνθρωπο έξοδο στην οθόνη. Φυσικά, μπορούμε επίσης να εισάγουμε ετικέτες πεδίων εάν χρειάζεται:

$ awk -F":" "( εκτύπωση "όνομα χρήστη: " $1 "\t\tuid: " $3" )" /etc/passwd

Ως αποτέλεσμα, βγάζουμε το εξής συμπέρασμα:

username: halt uid:7 username: operator uid:11 username: root uid:0 username: shutdown uid:6 username: sync uid:5 username: bin uid:1 ....κ.λπ.

Εξωτερικά σενάρια

Η μεταβίβαση σεναρίων στο awk ως ορίσματα γραμμής εντολών μπορεί να είναι βολική για μικρά προγράμματα μιας γραμμής, αλλά όταν πρόκειται για πολύπλοκα προγράμματα πολλαπλών γραμμών, είναι σίγουρα καλύτερο να συνθέσετε το σενάριο ως εξωτερικό αρχείο. Στη συνέχεια, μπορείτε να δείξετε awk σε αυτό το αρχείο σεναρίου χρησιμοποιώντας την επιλογή -f:

$ awk -f myscript.awk myfile.in

Η τοποθέτηση σεναρίων σε ξεχωριστά αρχεία κειμένου σάς επιτρέπει επίσης να επωφεληθείτε από τα πρόσθετα πλεονεκτήματα του awk. Για παράδειγμα, το ακόλουθο σενάριο πολλαπλών γραμμών κάνει το ίδιο πράγμα με ένα από τα προηγούμενα one-liners μας - εκτυπώνει το πρώτο πεδίο κάθε γραμμής από το /etc/passwd:

BEGIN ( FS=":" ) ( εκτύπωση $1 )

Η διαφορά μεταξύ αυτών των δύο μεθόδων είναι ο τρόπος με τον οποίο καθορίζουμε το διαχωριστικό πεδίου. Σε αυτό το σενάριο, το διαχωριστικό πεδίου καθορίζεται εσωτερικά από το ίδιο το πρόγραμμα (ρυθμίζοντας τη μεταβλητή FS), ενώ στο προηγούμενο παράδειγμά μας, το FS ρυθμίζεται περνώντας awk την επιλογή -F":" στη γραμμή εντολών. Συνήθως είναι καλύτερο να καθορίσετε το διαχωριστικό πεδίου μέσα στο ίδιο το σενάριο, απλώς και μόνο επειδή δεν θα σας ζητήσει να θυμάστε άλλο όρισμα γραμμής εντολών. Θα εξετάσουμε τη μεταβλητή FS με περισσότερες λεπτομέρειες αργότερα σε αυτό το άρθρο.

μπλοκ BEGIN και END

Συνήθως το awk εκτελεί κάθε μπλοκ στο κείμενο του σεναρίου μία φορά για κάθε γραμμή εισόδου. Ωστόσο, υπάρχουν συχνά καταστάσεις στον προγραμματισμό όπου πρέπει να εκτελέσετε τον κώδικα αρχικοποίησης πριν το awk ξεκινήσει την επεξεργασία κειμένου από ένα αρχείο εισόδου. Για τέτοιες περιπτώσεις, το awk παρέχει τη δυνατότητα ορισμού ενός μπλοκ BEGIN. Χρησιμοποιήσαμε το μπλοκ BEGIN στο προηγούμενο παράδειγμα. Επειδή το μπλοκ BEGIN υποβάλλεται σε επεξεργασία πριν το awk ξεκινήσει την επεξεργασία του αρχείου εισόδου, αυτό είναι ένα εξαιρετικό μέρος για την προετοιμασία μιας μεταβλητής FS (διαχωριστής πεδίου), την έξοδο μιας κεφαλίδας ή την προετοιμασία άλλων καθολικών μεταβλητών που θα χρησιμοποιηθούν αργότερα στο πρόγραμμα.

Το Awk παρέχει επίσης ένα άλλο ειδικό μπλοκ που ονομάζεται END block. Το Awk εκτελεί αυτό το μπλοκ αφού ολοκληρωθεί η επεξεργασία όλων των γραμμών στο αρχείο εισόδου. Συνήθως, ένα μπλοκ ΤΕΛΟΣ χρησιμοποιείται για την εκτέλεση τελικών υπολογισμών ή αποτελεσμάτων εξόδου που θα πρέπει να εμφανίζονται στο τέλος της ροής εξόδου.

Κανονικές εκφράσεις και μπλοκ

Το Awk σάς επιτρέπει να χρησιμοποιείτε κανονικές εκφράσεις για να εκτελέσετε επιλεκτικά συγκεκριμένα μπλοκ ενός προγράμματος ανάλογα με το εάν η τυπική έκφραση ταιριάζει ή όχι με την τρέχουσα γραμμή. Ακολουθεί ένα παράδειγμα σεναρίου που εκτυπώνει μόνο εκείνες τις γραμμές που περιέχουν την ακολουθία χαρακτήρων foo:

/foo/ (εκτύπωση)

Φυσικά, μπορείτε να χρησιμοποιήσετε πιο σύνθετες τυπικές εκφράσεις. Ακολουθεί ένα σενάριο που θα παράγει μόνο γραμμές που περιέχουν ένα float:

/+\.*/ ( εκτύπωση )

Εκφράσεις και μπλοκ

Υπάρχουν πολλοί άλλοι τρόποι για να εκτελέσετε επιλεκτικά ένα μπλοκ ενός προγράμματος. Μπορούμε να τοποθετήσουμε οποιαδήποτε έκφραση Boole πριν από ένα μπλοκ προγράμματος για να ελέγξουμε την εκτέλεση αυτού του μπλοκ. Το Awk θα εκτελέσει ένα μπλοκ προγράμματος μόνο εάν η προηγούμενη Boolean έκφραση αξιολογηθεί ως true. Το ακόλουθο παράδειγμα δέσμης ενεργειών θα παράγει το τρίτο πεδίο όλων των γραμμών όπου το πρώτο πεδίο είναι fred. Εάν το πρώτο πεδίο της τρέχουσας γραμμής δεν είναι fred, το awk θα συνεχίσει να επεξεργάζεται το αρχείο και δεν θα εκδώσει δήλωση εκτύπωσης για την τρέχουσα γραμμή:

$1 == "fred" (εκτύπωση 3 $)

Το Awk προσφέρει ένα πλήρες σύνολο τελεστών σύγκρισης, συμπεριλαμβανομένων των συνηθισμένων "==", "<", ">", "<=", ">=" και "!=". Επιπλέον, το awk παρέχει τους τελεστές "~" και "!~", που σημαίνουν "ταιριάζει" και "δεν ταιριάζει." Τοποθετούν τη μεταβλητή στα αριστερά του τελεστή και την κανονική έκφραση στα δεξιά της Ακολουθεί ένα παράδειγμα όπου εξάγεται μόνο το τρίτο πεδίο μιας γραμμής εάν το πέμπτο πεδίο της ίδιας γραμμής περιέχει τη ρίζα της ακολουθίας χαρακτήρων:

$5 ~ /root/ (εκτύπωση $3)

Δηλώσεις υπό όρους

Το Awk παρέχει επίσης πολύ ωραίες δηλώσεις τύπου C if. Εάν θέλετε, μπορείτε να ξαναγράψετε το προηγούμενο σενάριο χρησιμοποιώντας εάν:

( if ($5 ~ /root/) (εκτύπωση $3 ) )

Και τα δύο σενάρια λειτουργούν πανομοιότυπα. Στο πρώτο παράδειγμα, η δυαδική έκφραση είναι έξω από το μπλοκ, ενώ στο δεύτερο παράδειγμα, το μπλοκ εκτελείται για κάθε γραμμή εισόδου και εκτελούμε επιλεκτικά την εντολή εκτύπωσης χρησιμοποιώντας μια εντολή if και οι δύο μέθοδοι λειτουργούν και μπορείτε να επιλέξετε τη μία που συνδυάζεται καλύτερα με άλλα μέρη του σεναρίου.

Εδώ είναι ένα πιο περίπλοκο παράδειγμα μιας δήλωσης if στο awk. Όπως μπορείτε να δείτε, ακόμη και με περίπλοκες ένθετες προϋποθέσεις, εάν οι εντολές φαίνονται πανομοιότυπες με τις αντίστοιχες C:

( if ($1 == "foo") ( if ($2 == "foo") ( print "uno" ) else ( print "one" ) ) other if ($1 == "bar") ( print "two" ) other (εκτύπωση "τρία") )

Χρησιμοποιώντας τις προτάσεις if, μπορούμε να μετατρέψουμε αυτόν τον κώδικα:

! /matchme/ (εκτύπωση $1 $3 $4)( αν ($0 !~ /matchme/) ( εκτύπωση 1 $3 $4 ) )

Και τα δύο σενάρια θα εκτυπώσουν μόνο τις γραμμές που Δενπεριέχει την ακολουθία χαρακτήρων matchme . Και σε αυτήν την περίπτωση, επίσης, μπορείτε να επιλέξετε μια μέθοδο που λειτουργεί καλύτερα σε ένα συγκεκριμένο πρόγραμμα. Και οι δύο κάνουν το ίδιο πράγμα.

Το Awk σάς δίνει επίσης τη δυνατότητα να χρησιμοποιήσετε τους τελεστές Boolean "||" ("λογικό Ή") και "&&" ("λογικό ΚΑΙ"), το οποίο σας επιτρέπει να δημιουργείτε πιο σύνθετες εκφράσεις Boole:

($1 == "foo") && ($2 == "bar") ( εκτύπωση )

Αυτό το παράδειγμα θα παράγει μόνο γραμμές όπου το πρώτο πεδίο είναι foo Καιτο δεύτερο πεδίο είναι η γραμμή.

Αριθμητικές μεταβλητές!

Μέχρι στιγμής έχουμε εκτυπώσει είτε μεταβλητές συμβολοσειρών, ολόκληρες συμβολοσειρές ή συγκεκριμένα πεδία. Ωστόσο, το awk μας δίνει επίσης τη δυνατότητα να κάνουμε συγκρίσεις τόσο σε ακέραιους όσο και σε αριθμούς κινητής υποδιαστολής. Χρησιμοποιώντας μαθηματικές εκφράσεις, είναι πολύ εύκολο να γράψετε ένα σενάριο που μετράει τον αριθμό των κενών γραμμών σε ένα αρχείο. Εδώ είναι ένα τέτοιο σενάριο:

BEGIN ( x=0 ) /^$/ ( x=x+1 ) END (εκτύπωση "Βρέθηκαν " x " κενές γραμμές. :)" )

Στο μπλοκ BEGIN, αρχικοποιούμε την ακέραια μεταβλητή x στο μηδέν. Στη συνέχεια, κάθε φορά που το awk συναντά μια κενή γραμμή, θα εκτελεί την πρόταση x=x+1, αυξάνοντας το x κατά 1. Μόλις ολοκληρωθεί η επεξεργασία όλων των γραμμών, το μπλοκ ΤΕΛΟΣ θα εκτελεστεί και το awk θα εκτυπώνει το τελικό σύνολο, υποδεικνύοντας τον αριθμό των κενών γραμμών που βρέθηκαν.

Μεταβλητές συμβολοσειράς

Ένα από τα ωραία πράγματα με τις μεταβλητές awk είναι ότι είναι "απλές και πεζά". Ονομάζω τις μεταβλητές awk "string" επειδή όλες οι μεταβλητές awk αποθηκεύονται εσωτερικά ως συμβολοσειρές. Ταυτόχρονα, οι μεταβλητές awk είναι "απλές" επειδή μπορείτε να κάνετε μαθηματικά σε μια μεταβλητή και εάν περιέχει μια έγκυρη συμβολοσειρά αριθμών, η awk θα φροντίσει αυτόματα να μετατρέψει τη συμβολοσειρά σε αριθμό. Για να καταλάβετε τι εννοώ, ρίξτε μια ματιά σε αυτό το παράδειγμα:

x="1.01" # Κάναμε το x να περιέχει το *string* "1.01" x=x+1 # Μόλις προσθέσαμε 1 στη *string* print x # Αυτό είναι ένα σχόλιο, παρεμπιπτόντως :)

Το Awk θα παράγει:

2.01

Περίεργος! Αν και εκχωρήσαμε την τιμή συμβολοσειράς 1,01 στο x, μπορέσαμε να προσθέσουμε μία σε αυτήν. Δεν μπορούσαμε να το κάνουμε αυτό σε bash ή python. Πρώτα απ 'όλα, το bash δεν υποστηρίζει αριθμητική κινητής υποδιαστολής. Και ενώ το bash έχει μεταβλητές "string", δεν είναι "απλές". Για να κάνουμε μαθηματικά, το bash απαιτεί από εμάς να τυλίξουμε τους υπολογισμούς μας σε άσχημες κατασκευές $(). Εάν χρησιμοποιούσαμε python, θα έπρεπε να μετατρέψουμε ρητά τη συμβολοσειρά μας 1.01 σε τιμή κινητής υποδιαστολής πριν κάνουμε οποιουσδήποτε υπολογισμούς με αυτήν. Αν και αυτό δεν είναι δύσκολο, εξακολουθεί να είναι ένα επιπλέον βήμα. Στην περίπτωση του awk, όλα αυτά γίνονται αυτόματα, και κάνει τον κώδικα μας ωραίο και καθαρό. Αν χρειαζόταν να τετραγωνίσουμε το πρώτο πεδίο κάθε συμβολοσειράς εισόδου και να προσθέσουμε ένα σε αυτό, θα χρησιμοποιούσαμε ένα σενάριο όπως αυτό:

( εκτύπωση (1^2$)+1 )

Αν πειραματιστείτε λίγο, θα διαπιστώσετε ότι εάν μια μεταβλητή δεν περιέχει έγκυρο αριθμό, το awk θα αντιμετωπίσει αυτήν τη μεταβλητή ως αριθμητικό μηδέν κατά την αξιολόγηση μιας μαθηματικής παράστασης.

Πολλοί χειριστές

Ένα άλλο ωραίο χαρακτηριστικό του awk είναι το πλήρες σύνολο μαθηματικών τελεστών του. Εκτός από την τυπική πρόσθεση, αφαίρεση, πολλαπλασιασμό και διαίρεση, το awk μας δίνει τη δυνατότητα να χρησιμοποιήσουμε τον προηγουμένως αποδεδειγμένο τελεστή εκθέτη "^", τον τελεστή υπολοίπου διαίρεσης ακέραιου αριθμού "%" και πολλούς άλλους βολικούς τελεστές εκχώρησης δανεισμένους από το C.

Αυτοί περιλαμβάνουν τελεστές εκχώρησης πριν και μετά την αύξηση/φθίνουσα ανάθεση (i++, --foo), τους τελεστές ανάθεσης με πρόσθεση/αφαίρεση/πολλαπλασιασμό/διαίρεση (a+=3, b*=2, c/=2,2, d-=6,2) . Αλλά αυτό δεν είναι μόνο - έχουμε επίσης βολικούς τελεστές εκχώρησης με υπολογισμό του υπολοίπου της διαίρεσης και της εκθέσεως (a^=2, b%=4).

Διαχωριστές πεδίου

Το awk έχει το δικό του σύνολο ειδικών μεταβλητών. Ορισμένα από αυτά σας δίνουν τη δυνατότητα να ρυθμίσετε με ακρίβεια τον τρόπο λειτουργίας του awk, ενώ άλλα περιέχουν πολύτιμες πληροφορίες εισόδου. Έχουμε ήδη αγγίξει μια από αυτές τις ειδικές μεταβλητές, την FS. Όπως αναφέρθηκε προηγουμένως, αυτή η μεταβλητή σάς επιτρέπει να καθορίσετε την ακολουθία χαρακτήρων που το awk θα θεωρήσει ως διαχωριστικό πεδίου. Όταν χρησιμοποιήσαμε το /etc/passwd ως είσοδο, το FS ορίστηκε σε ":". Αυτό αποδείχθηκε αρκετό, αλλά το FS μας δίνει ακόμα μεγαλύτερη ευελιξία.

Η τιμή της μεταβλητής FS δεν χρειάζεται να είναι ένας μόνο χαρακτήρας. μπορεί να της εκχωρηθεί μια τυπική έκφραση που καθορίζει ένα μοτίβο χαρακτήρων οποιουδήποτε μήκους. Εάν επεξεργάζεστε πεδία που χωρίζονται από έναν ή περισσότερους χαρακτήρες καρτέλας, τότε το FS πρέπει να ρυθμιστεί ως εξής:

FS="\t+"

Παραπάνω χρησιμοποιήσαμε τον ειδικό χαρακτήρα τυπικής έκφρασης "+", που σημαίνει "μία ή περισσότερες εμφανίσεις του προηγούμενου χαρακτήρα".

Εάν τα πεδία διαχωρίζονται με λευκό διάστημα (ένα ή περισσότερα κενά ή καρτέλες), ίσως θέλετε να ορίσετε το FS στην ακόλουθη τυπική έκφραση:

FS="[[:space:]+]"

Αν και αυτή η ρύθμιση θα λειτουργήσει, δεν είναι απαραίτητη. Γιατί; Επειδή η προεπιλεγμένη τιμή του FS είναι ένας χαρακτήρας διαστήματος, ο οποίος ερμηνεύει το awk ως "ένα ή περισσότερα κενά ή καρτέλες". Στο συγκεκριμένο παράδειγμά μας, η προεπιλεγμένη τιμή FS είναι ακριβώς αυτό που χρειαζόμασταν!

Δεν υπάρχουν επίσης προβλήματα με σύνθετες κανονικές εκφράσεις. Ακόμα κι αν οι εγγραφές διαχωρίζονται από τη λέξη "foo" ακολουθούμενη από τρία ψηφία, η ακόλουθη τυπική έκφραση θα αναλύσει τα δεδομένα σωστά:

FS="foo"

Αριθμός πεδίων

Οι επόμενες δύο μεταβλητές που θα εξετάσουμε συνήθως δεν προορίζονται για εγγραφή, αλλά μάλλον για ανάγνωση και λήψη χρήσιμων πληροφοριών σχετικά με την είσοδο. Η πρώτη από αυτές είναι η μεταβλητή NF, που ονομάζεται επίσης αριθμός πεδίων. Το Awk ορίζει αυτόματα την τιμή αυτής της μεταβλητής στον αριθμό των πεδίων στην τρέχουσα εγγραφή. Μπορείτε να χρησιμοποιήσετε τη μεταβλητή NF για να εμφανίσετε μόνο ορισμένες γραμμές εισόδου:

NF == 3 ( εκτύπωση "υπάρχουν τρία πεδία σε αυτήν την καταχώρηση: " $0 )

Φυσικά, η μεταβλητή NF μπορεί επίσης να χρησιμοποιηθεί σε δηλώσεις υπό όρους, για παράδειγμα:

( if (NF > 2) ( εκτύπωση $1 " " $2 ":" $3 ) )

Αριθμός αρχείου

Μια άλλη βολική μεταβλητή είναι ο αριθμός εγγραφής (NR). Περιέχει πάντα τον αριθμό της τρέχουσας εγγραφής (το awk θεωρεί ότι η πρώτη εγγραφή είναι ο αριθμός εγγραφής 1). Μέχρι στιγμής έχουμε να κάνουμε με αρχεία εισόδου που περιέχουν μία εγγραφή ανά γραμμή. Σε τέτοιες περιπτώσεις, η NR θα αναφέρει επίσης τον τρέχοντα αριθμό γραμμής. Ωστόσο, όταν αρχίσουμε να χειριζόμαστε εγγραφές πολλαπλών γραμμών σε μεταγενέστερα άρθρα αυτής της σειράς, αυτό δεν θα ισχύει πλέον, επομένως πρέπει να είστε προσεκτικοί! Το NR μπορεί να χρησιμοποιηθεί όπως η μεταβλητή NF για την έξοδο μόνο συγκεκριμένων γραμμών εισόδου:

(NR< 10) || (NR >100) ( εκτύπωση "Βρισκόμαστε στον αριθμό ρεκόρ 1-9 ή 101 ή περισσότερο")

Άλλο παράδειγμα:

( #skip header if (NR > 10) ( τυπώστε "τώρα έρχονται οι πραγματικές πληροφορίες!" ) )

Το Awk παρέχει πρόσθετες μεταβλητές που μπορούν να χρησιμοποιηθούν για διάφορους σκοπούς. Θα εξετάσουμε αυτές τις μεταβλητές σε μελλοντικά άρθρα. Φτάσαμε στο τέλος της αρχικής μας εξερεύνησης του awk. Σε μελλοντικά άρθρα της σειράς, θα δείξω πιο προηγμένες λειτουργίες awk και θα ολοκληρώσουμε αυτήν τη σειρά με μια εφαρμογή awk πραγματικού κόσμου. Εν τω μεταξύ, εάν θέλετε να μάθετε περισσότερα, μπορείτε να ελέγξετε τους πόρους που αναφέρονται παρακάτω.



Ερωτήσεις;

Αναφέρετε ένα τυπογραφικό λάθος

Κείμενο που θα σταλεί στους συντάκτες μας: