Από Awk σε Perl#
Ξέρετε το awk. Σκέφτεστε με όρους pattern { action }, διαχωρίζετε κάθε γραμμή σε $1, $2, $3 χωρίς να το ζητάτε, μετράτε πράγματα με a[key]++, και πλαισιώνετε όλη την εργασία με BEGIN { } και END { }. Η Perl γράφτηκε εν μέρει ως «awk, αλλά μεγαλύτερο» - σχεδόν ό,τι κάνετε στο awk έχει μια άμεση μορφή στην Perl, και ύστερα η Perl συνεχίζει: πραγματικές δομές δεδομένων, πλήρες regex, αρθρώματα, και μια γλώσσα που δεν μένει από χώρο όταν το σενάριο μεγαλώνει.
Η μία ιδέα που πρέπει να κρατήσετε από την πρώτη γραμμή: η Perl είναι σχεδόν υπερσύνολο του awk. Ο βρόχος εγγραφών, τα πεδία, οι συσχετιστικοί πίνακες, οι δεσμευμένες λέξεις BEGIN/END, οι print και printf, οι length/substr/split
αντιστοιχίζονται όλα, συχνά με το ίδιο όνομα. Αυτό που αλλάζει είναι ότι τα πεδία γίνονται ένας πραγματικός πίνακας
@Fπου μπορείτε να κάνετεpushκαιpop, ο συσχετιστικός πίνακας γίνεται ένας κατακερματισμός της Perl που μπορείτε να εμφωλεύσετε, και η μηχανή regex είναι PCRE αντί για POSIX ERE. Αυτός ο οδηγός ξεκινά με τις ένα-προς-ένα αντιστοιχίσεις και επισημαίνει τα λίγα σημεία όπου η αναλογία διαρρέει.
Every runnable example here was executed on pperl, a Rust reimplementation of Perl 5.42; the # ... comments show its real output. Start scripts with:
use v5.42;
Αυτή η μία γραμμή ενεργοποιεί το strict, τα warnings και την ενσωματωμένη say (μια print με τελική νέα γραμμή), το σύγχρονο σύνολο χαρακτηριστικών που χρησιμοποιείται παντού.
Σημείωση
Διακόπτες one-liner σε αυτό το build του pperl Ο φυσικός δίδυμος του awk στην Perl είναι το one-liner: perl -ne, perl -ane, και perl -F, -ane. Αυτοί οι διακόπτες είναι σωστή perl5 5.42 και εμφανίζονται σε όλον αυτόν τον οδηγό ως η ιδιωματική μορφή. Όμως η οικογένεια διακοπτών έμμεσου βρόχου (-n, -p, -a, -F, -i, -l) δεν αναγνωρίζεται ακόμη από αυτό το build του pperl - μόνο το -e αναγνωρίζεται. Έτσι τα παραδείγματα one-liner παρακάτω εμφανίζονται χωρίς έξοδο, και καθένα συνοδεύεται από μια μορφή πλήρους σεναρίου με ρητό βρόχο (while (<$fh>) { ... }) που όντως τρέχει στο pperl σήμερα και φέρει την επαληθευμένη έξοδο. Χρησιμοποιήστε τη μορφή πλήρους σεναρίου μέχρι να προστεθούν οι διακόπτες.
Πώς να το διαβάσετε#
Ο βρόχος γραμμής/εγγραφής - το έμμεσο
{ ... }του awk γίνεταιwhile (<$fh>)και$_.Πεδία και διαχωρισμός - τα
$1/$NF/NF/FSγίνονται@F,$F[0],split,-F.Regex και αντικατάσταση - τα
gsub/sub/matchγίνονταιs////=~, ένα γνήσιο υπερσύνολο.Διευθύνσεις και εύρη - τα
/re/,cond { }και/a/,/b/γίνονται μεταθεματικόifκαι το flip-flop.I/O, σωληνώσεις, επιτόπια επεξεργασία -
getline, ανακατεύθυνση και-i.One-liners και διακόπτες -
-n,-a,-F,BEGIN/END.Ροή ελέγχου -
next,for, οι μεταθεματικές μορφές.Μεταβλητές και δεδομένα - οι συσχετιστικοί πίνακες γίνονται κατακερματισμοί, η ευτυχής αντιστοίχιση.
Παγίδες ερχόμενοι από το awk - ρίξτε μια ματιά πριν γράψετε.
Ο βρόχος γραμμής/εγγραφής#
Το awk τρέχει το πρόγραμμά σας μία φορά ανά εγγραφή εισόδου, με την εγγραφή στο $0 και τη δράση στο { ... }. Το αντίστοιχο της Perl είναι ένας ρητός βρόχος με την εγγραφή στο $_, την έμμεση μεταβλητή θέματος. Ο διακόπτης -n αναπαράγει το «τρέξε αυτό το μπλοκ ανά γραμμή» του awk· το NR (αριθμός εγγραφής) του awk είναι το $. της Perl.
awk '{ print }' input.txt
perl -ne 'print' input.txt
Η εκτελέσιμη μορφή πλήρους σεναρίου του ίδιου βρόχου - αυτή που τρέχει στο pperl σήμερα - ανοίγει το αρχείο και το διατρέχει ρητά. Το $_ είναι η τρέχουσα εγγραφή, ακριβώς όπως το $0 του awk:
use v5.42;
open my $fh, '<', '/tmp/scores.txt' or die "open: $!";
while (<$fh>) { # each line lands in $_, like awk's $0
chomp;
say "line $. : $_"; # $. is awk's NR
}
# line 1 : alice 85 90
# line 2 : bob 70 60
# line 3 : carol 95 100
# line 4 : alice 50 55
(Το αρχείο εισόδου περιείχε alice 85 90, bob 70 60, carol 95 100, alice 50 55.) Η παγίδα: μια γραμμή που διαβάζεται με <$fh> κρατά την τελική νέα γραμμή της, σε αντίθεση με το $0 του awk, από το οποίο έχει αφαιρεθεί ο διαχωριστής εγγραφών. Καλέστε chomp για να την αφαιρέσετε (το chomp είναι το πιο κοντινό πράγμα στο «το awk ήδη αφαίρεσε τη νέα γραμμή για σένα»). Ο αριθμός εγγραφής είναι $. = το NR του awk· όταν διαβάζετε πολλά αρχεία με <>, το $. συνεχίζει να μετρά σε όλα τους, οπότε ο μηδενισμός του FNR (μετρητής ανά αρχείο) του awk είναι κάτι που οργανώνετε εσείς ελέγχοντας το eof.
Πεδία και διαχωρισμός#
Αυτή είναι η καρδιά του awk, και η Perl σάς δίνει την ίδια εικόνα με μία ανατροπή: τα πεδία ζουν σε έναν πραγματικό πίνακα @F, οπότε το $1 του awk είναι το $F[0] της Perl (μηδενοβάσει), το $0 είναι το $_, και το NF είναι το πλήθος scalar @F. Υπό τον διακόπτη -a η Perl αυτοδιαχωρίζει κάθε γραμμή σε @F ακριβώς όπως το awk αυτοδιαχωρίζει σε $1..$NF· το εκτελέσιμο αντίστοιχο είναι ένα ρητό split.
awk '{ print $1, NF }' input.txt # first field, field count
awk -F, '{ print $1 }' input.txt # comma separator (FS)
perl -ane 'print "$F[0] @{[scalar @F]}\n"' input.txt # -a fills @F
perl -F, -ane 'print "$F[0]\n"' input.txt # -F sets the split pattern
Η μορφή πλήρους σεναρίου κάνει τον διαχωρισμό η ίδια. Το γυμνό split χωρίς ορίσματα διαχωρίζει το $_ βάσει κενών χαρακτήρων και απορρίπτει τα αρχικά κενά - ακριβώς το προεπιλεγμένο FS του awk:
use v5.42;
open my $fh, '<', '/tmp/scores.txt' or die "open: $!";
while (<$fh>) {
my @F = split; # awk's automatic field split
say "$F[0] has ", scalar(@F) - 1, " scores"; # $F[0]=$1, @F=NF
}
# alice has 2 scores
# bob has 2 scores
# carol has 2 scores
# alice has 2 scores
Η αριθμητική κατά μήκος των πεδίων είναι η καθημερινή δράση print $1, $2+$3 του awk, και διαβάζεται σχεδόν πανομοιότυπα:
use v5.42;
open my $fh, '<', '/tmp/scores.txt' or die "open: $!";
while (<$fh>) {
my @F = split;
say "$F[0]: ", $F[1] + $F[2]; # awk: print $1, $2+$3
}
# alice: 175
# bob: 130
# carol: 195
# alice: 105
Το $NF (το τελευταίο πεδίο) του awk είναι ο αρνητικός δείκτης $F[-1] της Perl, και ένα μη προεπιλεγμένο FS είναι το όρισμα μοτίβου του split:
use v5.42;
open my $fh, '<', '/tmp/data.csv' or die "open: $!"; # alice,85,90 ...
while (<$fh>) {
chomp;
my @F = split /,/; # awk -F,
say $F[-1]; # awk's $NF: last field
}
# 90
# 60
# 100
Για να ενώσετε ξανά τα πεδία με έναν διαχωριστή (το OFS του awk), ορίστε το $, (τον διαχωριστή πεδίων εξόδου που η print/say εισάγει ανάμεσα στα ορίσματα της λίστας της):
use v5.42;
open my $fh, '<', '/tmp/data.csv' or die "open: $!";
while (<$fh>) {
chomp;
my @F = split /,/;
local $, = "|"; # OFS
say @F; # join the list with OFS
}
# alice|85|90
# bob|70|60
# carol|95|100
Η παγίδα: τα πεδία είναι μηδενοβάσει. Το $1 του awk είναι $F[0], το $2 είναι $F[1], και το $0 (όλη η εγγραφή) είναι $_, όχι στοιχείο του @F. Το NF είναι scalar @F (ή $#F + 1)· το τελευταίο πεδίο είναι $F[-1], όχι $F[NF]. Και το split με ένα κενό ως συμβολοσειρά (split ' ') είναι η ειδική λειτουργία κενών-και-περικοπής· το split / / (ένα regex με ένα κενό) είναι κυριολεκτικό και δεν περικόπτει τα αρχικά κενά. Το σκέτο split χωρίς όρισμα είναι η προεπιλεγμένη λειτουργία τύπου awk που θέλετε τις περισσότερες φορές.
Regex και αντικατάσταση#
Τα sub, gsub, match και ~ του awk αντιστοιχίζονται όλα στη μία σύνταξη regex της Perl: το =~ δένει ένα μοτίβο σε μια συμβολοσειρά, το s/// αντικαθιστά, το s///g είναι καθολικό (το gsub έναντι του sub του awk). Η μηχανή της Perl είναι PCRE, ένα γνήσιο υπερσύνολο του POSIX ERE του awk, οπότε κάθε μοτίβο awk λειτουργεί και η Perl προσθέτει οπισθοαναφορές, lookaround, επώνυμες συλλήψεις και τις σημαίες /e, /r, /x για τις οποίες το awk δεν έχει αντίστοιχο.
awk '/^alice/ { sub(/alice/, "ALICE"); print }' input.txt
perl -ne 'if (/^alice/) { s/alice/ALICE/; print }' input.txt
Η μορφή πλήρους σεναρίου:
use v5.42;
open my $fh, '<', '/tmp/scores.txt' or die "open: $!";
while (<$fh>) {
next unless /^alice/; # awk: /^alice/ { ... }
s/alice/ALICE/; # awk: sub(/alice/, "ALICE") (first match)
print;
}
# ALICE 85 90
# ALICE 50 55
Χρησιμοποιήστε s///g για το gsub (κάθε αντιστοιχία) του awk, και οι ομάδες σύλληψης καταλήγουν στα $1, $2 ακριβώς όπως το match του awk γεμίζει τα RSTART/RLENGTH συν τον πίνακα του gawk. Η σημαία /e εκτελεί αυθαίρετη Perl στην αντικατάσταση, κάτι που το awk δεν μπορεί να κάνει:
use v5.42;
my $s = "items: 3 and 4";
(my $t = $s) =~ s/(\d+)/$1 * 10/ge; # /e: replacement is Perl code
say $t; # items: 30 and 40
Οι length, substr, index και οι συναρτήσεις πεζών/κεφαλαίων αντιστοιχίζονται κατ” όνομα - προσέξτε την ευρετηρίαση:
use v5.42;
my $s = "alice";
say length $s; # 5 (awk length($s))
say substr $s, 0, 3; # ali (awk substr($s,1,3) - awk is 1-based!)
say uc $s; # ALICE (awk toupper($s))
Η παγίδα: η substr είναι μηδενοβάσει ενώ η substr του awk είναι βάσει του ένα, οπότε το substr($s,1,3) του awk είναι substr($s,0,3) στην Perl. Και το s/// επεξεργάζεται τον στόχο του επιτόπια και επιστρέφει το πλήθος των αντικαταστάσεων, όχι τη νέα συμβολοσειρά - οπότε το my $new = ($s =~ s/a/b/) βάζει έναν αριθμό στο $new. Αντιγράψτε πρώτα ((my $t = $s) =~ s/.../.../) ή χρησιμοποιήστε τη σημαία /r για να πάρετε μια φρέσκια συμβολοσειρά. Οι κλάσεις χαρακτήρων POSIX ([[:digit:]]) λειτουργούν, αλλά οι συντομογραφίες της Perl (\d, \w, \s) είναι συντομότερες και αυτό που θα δείτε στον κώδικα Perl.
Διευθύνσεις και εύρη#
Ένας κανόνας awk είναι pattern { action }: η δράση τρέχει μόνο σε εγγραφές που ταιριάζουν με το μοτίβο. Στην Perl αυτό το μοτίβο είναι απλώς μια συνθήκη στην εντολή - ένα μεταθεματικό if που ελέγχει το $_. Ένα γυμνό /re/ ταιριάζει έναντι του $_, ένας αριθμητικός έλεγχος χρησιμοποιεί το $. (το NR του awk), και το εύρος /start/,/end/ του awk είναι ο χειριστής flip-flop /start/ .. /end/ της Perl.
awk 'NR==2' input.txt # print record 2
awk '/banana/' input.txt # print matching records
awk '/bob/,/carol/' input.txt # range, inclusive
perl -ne 'print if $. == 2' input.txt
perl -ne 'print if /banana/' input.txt
perl -ne 'print if /bob/ .. /carol/' input.txt
Το flip-flop πλήρους σεναρίου, αληθές από τη γραμμή που ταιριάζει με το αριστερό μοτίβο έως τη γραμμή που ταιριάζει με το δεξί, συμπεριλαμβανομένων - ακριβώς το εύρος δύο μοτίβων του awk:
use v5.42;
open my $fh, '<', '/tmp/scores.txt' or die "open: $!";
while (<$fh>) {
print if /bob/ .. /carol/; # awk: /bob/,/carol/
}
# bob 70 60
# carol 95 100
Η παγίδα: ένα γυμνό pattern χωρίς δράση στο awk σημαίνει «εκτύπωσε την εγγραφή»· στην Perl ο βρόχος είναι ρητός, οπότε γράφετε εσείς την print (ή say). Και σε έναν λογικό έλεγχο το .. είναι ο χειριστής flip-flop (εύρους), όχι ο χειριστής εύρους λίστας (το 1 .. 10 χτίζει μια λίστα). Η Perl τα ξεχωρίζει βάσει περιβάλλοντος: στη βαθμωτή θέση ενός if, το .. είναι ο επιλογέας εύρους γραμμών με κατάσταση που αντικατοπτρίζει το addr1,addr2 του awk.
I/O, σωληνώσεις, επιτόπια επεξεργασία#
Το awk διαβάζει αυτόματα κάθε αρχείο που ονομάζεται στη γραμμή εντολών του και έχει το getline για ρητές αναγνώσεις. Το <> (ο χειριστής διαμαντιού) της Perl διαβάζει με τη σειρά κάθε αρχείο στο @ARGV - η ίδια προεπιλογή - και το <$fh> είναι το ρητό getline. Η εγγραφή σε μια εντολή ή η ανάγνωση από μία (τα print | "cmd" και "cmd" | getline του awk) είναι ένας περιγραφέας σωλήνωσης.
awk '{ print > "out.txt" }' input.txt # redirect output
awk '{ print | "sort" }' input.txt # pipe to a command
use v5.42;
open my $out, '>', '/tmp/out.txt' or die "write: $!";
open my $in, '<', '/tmp/scores.txt' or die "read: $!";
while (<$in>) {
print {$out} $_; # awk: print > "out.txt"
}
close $out;
Για σωληνώσεις, το open my $fh, '|-', 'sort' γράφει στην είσοδο μιας εντολής και το open my $fh, '-|', 'ls', '-l' διαβάζει την έξοδο μιας εντολής - το | "cmd" του awk και προς τις δύο κατευθύνσεις.
Το awk δεν έχει ενσωματωμένη επιτόπια επεξεργασία· καταφεύγετε σε ανακάτεμα tmp-αρχείου ή στο GNU gawk -i inplace. Η Perl το γράφει -i σε ένα one-liner:
perl -i -pe 's/red/crimson/' file.txt # edit in place
Το εκτελέσιμο αντίστοιχο σήμερα είναι μια ρητή ανάγνωση-τροποποίηση-εγγραφή - ρουφήξτε τις γραμμές, μετασχηματίστε, γράψτε πίσω - που είναι ακριβώς αυτό που κάνει το -i στο παρασκήνιο:
use v5.42;
my $path = '/tmp/inplace.txt'; # holds: red green blue
open my $in, '<', $path or die "read: $!";
my @lines = <$in>; # slurp all lines (list context)
close $in;
s/e/E/g for @lines; # transform each line's $_
open my $out, '>', $path or die "write: $!";
print {$out} @lines; # write them back
close $out;
# file now holds: rEd / grEEn / bluE
Η παγίδα: η open επιστρέφει ψευδές σε αποτυχία αντί να ματαιώσει, οπότε το ιδίωμα or die "...: $!" είναι υποχρεωτικό - το $! είναι η συμβολοσειρά σφάλματος του συστήματος, η σιωπηλή αποτυχία του awk γινόμενη ρητή. Και το print {$out} ... χρειάζεται τα άγκιστρα γύρω από τον περιγραφέα όταν είναι μεταβλητή· η γυμνή μορφή print FH ... (χωρίς κόμμα) είναι για επώνυμους περιγραφείς, κάτι που αποτελεί συχνό σκόνταμμα της πρώτης μέρας.
One-liners και διακόπτες#
Το one-liner είναι το οικείο έδαφος του awk, και της Perl επίσης. Η οικογένεια διακοπτών που αναπαράγει το awk: το -e παρέχει το πρόγραμμα, το -n το τυλίγει σε έναν βρόχο ανά εγγραφή (το έμμεσο { } του awk), το -p κάνει το ίδιο με μια αυτόματη εκτύπωση στο τέλος κάθε κύκλου, το -a αυτοδιαχωρίζει σε @F (ο αυτόματος διαχωρισμός πεδίων του awk), το -F ορίζει το μοτίβο διαχωρισμού (το FS του awk), και το -l χειρίζεται τα τέλη γραμμών (η ευκολία ORS/RS του awk). Τα BEGIN { } και END { } είναι οι ίδιες δεσμευμένες λέξεις με το awk, τρέχοντας πριν και μετά τον βρόχο.
awk '/error/ { print }' log.txt # print error records
awk '{ s += $NF } END { print s }' input.txt # sum the last field
awk -F, '{ print $1 }' input.txt # first CSV field
perl -ne 'print if /error/' log.txt
perl -ane 'END { print "$s\n" } $s += $F[-1]' input.txt
perl -F, -ane 'print "$F[0]\n"' input.txt
Αυτά εμφανίζονται χωρίς έξοδο επειδή οι διακόπτες έμμεσου βρόχου δεν αναγνωρίζονται ακόμη από αυτό το build του pperl (δείτε τη σημείωση στην αρχή). Καθένας αντιστοιχίζεται σε μια επαληθευμένη μορφή ρητού βρόχου: το perl -ne 'CODE' είναι while (<$fh>) { CODE }, το -ane προσθέτει my @F = split στην αρχή, και τα μπλοκ BEGIN/END λειτουργούν σε ένα πλήρες σενάριο ακριβώς όπως στο awk. Η εκτελέσιμη μορφή «άθροισε μια στήλη με BEGIN/END»:
use v5.42;
my $n = 0;
my $sum = 0;
BEGIN { say "start" } # runs before the loop, like awk BEGIN
END { say "lines=$n sum=$sum" } # runs after, like awk END
open my $fh, '<', '/tmp/scores.txt' or die "open: $!";
while (<$fh>) {
my @F = split;
$n++;
$sum += $F[1]; # awk: sum += $2
}
# start
# lines=4 sum=300
Η παγίδα: μέχρι να προστεθούν οι διακόπτες στο pperl, γράψτε τον ρητό βρόχο (τρέχει σήμερα και είναι ούτως ή άλλως αυτό στο οποίο αναπτύσσονται οι διακόπτες), και συμβουλευτείτε τον οδηγό One-Liners για τον πλήρη κατάλογο διακοπτών και δεκάδες συνταγές - είναι το πιο αποδοτικό πράγμα που μπορείτε να διαβάσετε ερχόμενοι από υπόβαθρο awk. Η Perl έχει επίσης πλήρεις υπορουτίνες, αναφορές, αρθρώματα και OO αν το σενάριό σας ξεπεράσει ένα one-liner· δείτε τον οδηγό Αντικειμενοστραφούς Προγραμματισμού και τους άλλους οδηγούς coming-from.
Ροή ελέγχου#
Οι δεσμευμένες λέξεις ελέγχου του awk αντιστοιχούν στις αντίστοιχες της Perl σχεδόν λέξη προς λέξη. Το next του awk (παράλειψη προς την επόμενη εγγραφή) είναι το next της Perl· το break/continue στους βρόχους του awk είναι το last/next της Perl· το for (k in arr) του awk γίνεται ένα for της Perl πάνω στα keys. Οι αγκύλες και το ; είναι ίδια· η Perl προσθέτει τις μεταθεματικές μορφές που διαβάζονται σαν μοτίβα του awk.
awk '{ if ($2 < 70) next; print }' input.txt
use v5.42;
open my $fh, '<', '/tmp/scores.txt' or die "open: $!";
while (<$fh>) {
my @F = split;
next if $F[1] < 70; # awk: if ($2 < 70) next
print;
}
# alice 85 90
# carol 95 100
Η παγίδα: οι χειριστές σύγκρισης της Perl έρχονται σε δύο οικογένειες και επιλέγετε βάσει του τύπου των τελεστέων, ενώ το awk έχει μόνο </== και για τους δύο. Οι αριθμοί χρησιμοποιούν ==, <, >, <=>· οι συμβολοσειρές χρησιμοποιούν eq, lt, gt, cmp. Το awk αποφασίζει αριθμητική-έναντι-συμβολοσειρά σύγκριση βάσει των τιμών κατά τον χρόνο εκτέλεσης· η Perl σάς κάνει να επιλέξετε τον χειριστή. Η χρήση του == σε συμβολοσειρές (ή του eq σε αριθμούς) είναι ένα συχνό, σιωπηλό σφάλμα - το "abc" == "xyz" είναι αληθές στην Perl (και τα δύο μετατρέπονται αριθμητικά σε 0), κάτι που σχεδόν ποτέ δεν είναι αυτό που εννοούσατε.
Μεταβλητές και δεδομένα#
Αυτή είναι η πιο ευτυχής αντιστοίχιση στον οδηγό: ο συσχετιστικός πίνακας του awk είναι ένας κατακερματισμός της Perl, και τα καθημερινά ιδιώματα είναι σχεδόν πανομοιότυπα. Το count[$1]++ του awk είναι το $count{$F[0]}++ της Perl· το for (k in count) είναι for my $k (keys %count)· το if (k in count) είναι exists $count{$k}. Η μόνη μετατόπιση είναι το sigil - ολόκληρος ο κατακερματισμός είναι %count, αλλά μία τιμή είναι $count{$key}.
awk '{ total[$1] += $2 + $3 }
END { for (k in total) print k, total[k] }' input.txt
use v5.42;
open my $fh, '<', '/tmp/scores.txt' or die "open: $!";
my %total;
while (<$fh>) {
my @F = split;
$total{$F[0]} += $F[1] + $F[2]; # awk: total[$1] += $2 + $3
}
for my $name (sort keys %total) { # awk END loop over the array
say "$name $total{$name}";
}
# alice 280
# bob 130
# carol 195
Το ιδίωμα δύο αρχείων NR==FNR - φόρτωσε κλειδιά από το πρώτο αρχείο, μετά έλεγξε την ιδιότητα μέλους στο δεύτερο - είναι ένας ρητός βρόχος ανά αρχείο στην Perl, που είναι σαφέστερος από το one-liner του awk που αντικαθιστά:
use v5.42;
my %seen;
open my $f1, '<', '/tmp/data.csv' or die "open: $!";
while (<$f1>) {
my ($k) = split /,/; # first field only
$seen{$k} = 1;
}
close $f1;
open my $f2, '<', '/tmp/scores.txt' or die "open: $!";
while (<$f2>) {
my ($k) = split;
print if $seen{$k}; # awk: ($1 in seen)
}
# alice 85 90
# bob 70 60
# carol 95 100
# alice 50 55
Η παγίδα: ένας κατακερματισμός δεν έχει εγγενή σειρά (το for (k in arr) του awk είναι επίσης χωρίς σειρά, οπότε αυτό δεν θα σας εκπλήξει), οπότε επαναλαμβάνετε με sort keys %h όταν θέλετε σταθερή σειρά. Η ιδιότητα μέλους είναι exists $h{$k}, όχι το k in arr του awk - και απλώς το να διαβάσετε το $h{$k} για να το ελέγξετε θα αυτο-δημιουργήσει το κλειδί σε ύπαρξη σε κάποια περιβάλλοντα, ενώ το exists ποτέ δεν το κάνει. Οι αριθμοί και οι συμβολοσειρές αυτο-εξαναγκάζονται στην Perl όπως στο awk, αλλά θυμηθείτε τον διαχωρισμό == έναντι eq από τη Ροή ελέγχου.
Παγίδες ερχόμενοι από το awk#
Οι παγίδες, συγκεντρωμένες για μια τελική ματιά πριν γράψετε:
Τα πεδία είναι μηδενοβάσει. Το
$1του awk είναι$F[0], το$2είναι$F[1], και όλη η εγγραφή$0είναι$_. ΤοNFείναιscalar @F· το τελευταίο πεδίο είναι$F[-1], όχι$F[NF].Το
<$fh>κρατά την τελική νέα γραμμή, σε αντίθεση με το$0του awk. Κάντεchompγια να την αφαιρέσετε.Η
substrείναι μηδενοβάσει, ενώ του awk είναι βάσει του ένα: τοsubstr($s,1,3)του awk είναιsubstr($s,0,3)στην Perl.Το
s///επιστρέφει ένα πλήθος, όχι τη νέα συμβολοσειρά. Τοmy $x = $s =~ s/a/b/βάζει το πλήθος αντικαταστάσεων στο$x. Αντιγράψτε πρώτα, ή χρησιμοποιήστε τη σημαία/rγια να πάρετε μια νέα συμβολοσειρά.Δύο οικογένειες σύγκρισης. Οι αριθμοί χρησιμοποιούν
==/</<=>· οι συμβολοσειρές χρησιμοποιούνeq/lt/cmp. Το μοναδικό==/<του awk χωρίζεται στα δύο, επιλεγόμενο βάσει χειριστή, όχι βάσει τιμής. Το"abc" == "xyz"είναι αληθές (και τα δύο μετατρέπονται αριθμητικά σε 0).Το γυμνό
splitείναι η προεπιλεγμένη λειτουργία τύπου awk. Τοsplit(χωρίς ορίσματα) διαχωρίζει το$_βάσει κενών χαρακτήρων και αφαιρεί τα αρχικά κενά. Τοsplit / /(ένα regex με ένα κενό) είναι κυριολεκτικό και δεν αφαιρεί - χρησιμοποιήστε το σκέτοsplitγια το προεπιλεγμένοFSτου awk.Η ιδιότητα μέλους είναι
exists $h{$k}, όχιk in arr. Ο έλεγχος ενός κλειδιού μέσω ανάγνωσης του$h{$k}μπορεί να το αυτο-δημιουργήσει· τοexistsποτέ δεν το κάνει.Η
openδεν ματαιώνει σε αποτυχία. Χρησιμοποιήστεopen my $fh, '<', $path or die "...: $!". Το$!είναι η συμβολοσειρά σφάλματος του συστήματος.Οι διακόπτες έμμεσου βρόχου (
-n/-p/-a/-F/-i/-l) δεν αναγνωρίζονται ακόμη από αυτό το build τουpperl. Μόνο το-eλειτουργεί σήμερα. Γράψτε τον ρητό βρόχοwhile (<$fh>) { my @F = split; ... }, που είναι ακριβώς αυτό στο οποίο αναπτύσσονται οι διακόπτες, μέχρι να προστεθούν.