Προοδευτικές συνταγές#

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

Οι αναγνώστες που έρχονται από awk/sed θα πρέπει να αναγνωρίσουν τις πρώτες ενότητες· το ενδιαφέρον υλικό ξεκινά γύρω από τις Αναγωγές σε γραμμές και τα Φίλτρα παραθύρου περιβάλλοντος.

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

Η αφετηρία: -e και -E#

Το συντομότερο μονόγραμμο. Χωρίς βρόχο I/O, χωρίς διάσπαση πεδίων - απλώς ένα πρόγραμμα που εκτελείται μία φορά.

pperl -e 'print 2 ** 32, "\n"'                    # 4294967296
pperl -E 'say 2 ** 32'                            # same, with -E/say
pperl -E 'say for 1 .. 5'                         # 1\n2\n3\n4\n5

Το , στο print διαχωρίζει ορίσματα· ο διαχωριστής πεδίων εξόδου $, (προεπιλεγμένα κενός) μπαίνει ανάμεσά τους.

Φιλτράρισμα: -n + print if#

Το -n τυλίγει το πρόγραμμα σε έναν βρόχο ανάγνωσης πάνω σε κάθε γραμμή κάθε αρχείου εισόδου (ή στο STDIN). Δεν τυπώνεται τίποτα εκτός αν το πει το πρόγραμμα.

# Sample input
$ printf 'gate\napple\nwhat\nkite\n' > words.txt

pperl -ne 'print if /at/' words.txt               # gate, what
pperl -ne 'print unless /e/' words.txt            # what
pperl -ne 'print if /^[aeiou]/' words.txt         # apple

Η αντιστοίχιση regex γίνεται κατά του $_ από προεπιλογή· το /at/ είναι συντομογραφία του $_ =~ m/at/.

Πολλαπλές συνθήκες#

# Lines containing both "ERROR" and "timeout"
pperl -ne 'print if /ERROR/ && /timeout/' app.log

# Lines containing neither
pperl -ne 'print if !/ERROR/ && !/timeout/' app.log

# Events A, B, C appearing in order on one line
pperl -ne 'print if /A.*B.*C/' events.log

Με αριθμό γραμμής#

pperl -ne 'print if $. == 1'                      # head -n 1
pperl -ne 'print if $. <= 10'                     # head -n 10
pperl -ne 'print if 17 .. 30'                     # lines 17-30 (range op)
pperl -ne 'print if /START/ .. /END/'             # regex range, inclusive
pperl -ne 'print unless $. % 2'                   # even lines

Ο τελεστής εύρους .. σε βαθμωτό περιβάλλον είναι flip-flop: συγκρίνεται με το $. όταν και τα δύο άκρα είναι ακέραιοι, με το $_ όταν είναι μοτίβα. Δείτε το perlop.

Με μήκος#

Χρησιμοποιήστε -l ώστε το μετρούμενο μήκος να αποκλείει τον τελικό χαρακτήρα αλλαγής γραμμής.

pperl -lne 'print if length >= 80' src.c          # long lines
pperl -lne 'print if length() < 5' words.txt      # short lines

Σκέτο length χωρίς όρισμα εφαρμόζεται στο $_.

Αντικατάσταση: -p + s///#

Το -p είναι το -n συν ένα σιωπηρό print μετά από κάθε επανάληψη. Χρησιμοποιήστε το όταν η έξοδος είναι η (πιθανώς τροποποιημένη) είσοδος.

# Replace every "foo" with "bar"
pperl -pe 's/foo/bar/g' input.txt

# First occurrence per line only
pperl -pe 's/foo/bar/' input.txt

# Conditional: replace only on lines that also match BAZ
pperl -pe 's/foo/bar/g if /BAZ/' input.txt

Μετασχηματισμοί πεζών-κεφαλαίων#

pperl -nle 'print uc'                              # to uppercase
pperl -nle 'print lc'                              # to lowercase
pperl -nle 'print ucfirst lc'                      # Sentence case
pperl -ple 's/(\w+)/\u$1/g'                        # Title Case Per Word

Τα uc, lc και ucfirst χωρίς όρισμα λειτουργούν επί του $_.

Κανονικοποίηση λευκών χαρακτήρων#

pperl -ple 's/^\s+//'                              # trim left
pperl -ple 's/\s+$//'                              # trim right
pperl -ple 's/^\s+|\s+$//g'                        # trim both
pperl -ple 's/\s+/ /g'                             # collapse runs
pperl -ne  'print if /\S/'                         # drop blank lines

Μετατροπή τέλους γραμμής#

pperl -pe 's/\r\n/\n/g' win.txt                    # DOS  → UNIX
pperl -pe 's/(?<!\r)\n/\r\n/g' unix.txt            # UNIX → DOS

Η οπίσθια διεκδίκηση (?<!\r) αποφεύγει την παραγωγή \r\r\n όταν η είσοδος είναι ήδη DOS-κωδικοποιημένη. Δείτε το regex-recipes για διεκδικήσεις γύρω σε βάθος.

Δουλειά προσανατολισμένη στα πεδία: -a και -F#

Το -a διασπά αυτόματα κάθε γραμμή στο @F. Το -F αλλάζει τον οριοθέτη.

$ cat table.txt
brown bread mat hair 42
blue cake mug shirt -7
yellow banana window shoes 3.14

# Second field
pperl -lane 'print $F[1]' table.txt
# bread, cake, banana

# Last field
pperl -lane 'print $F[-1]' table.txt
# 42, -7, 3.14

# Count fields per line
pperl -lane 'print scalar @F' table.txt
# 5, 5, 5

# Lines whose last field is negative
pperl -lane 'print if $F[-1] < 0' table.txt
# blue cake mug shirt -7

Προσαρμοσμένος οριοθέτης#

# /etc/passwd: print username (field 1) and shell (last field)
pperl -F: -lane 'print "$F[0] $F[-1]"' /etc/passwd

# Tab-separated
pperl -F'\t' -lane 'print $F[2]' metrics.tsv

# Comma or semicolon, one or more
pperl -F'[,;]+' -lane 'print scalar @F' mixed.csv

Το γνήσιο CSV (πεδία σε εισαγωγικά με ενσωματωμένα κόμματα) δεν είναι δουλειά για το -F. Χρησιμοποιήστε -MText::CSV - δείτε το numeric για το μοτίβο.

Επανένωση πεδίων#

Η παρεμβολή του @F μέσα σε διπλά εισαγωγικά χρησιμοποιεί το $" (προεπιλογή: ένα διάστημα) ως διαχωριστή.

# Reverse field order, space-separated
pperl -lane 'print "@{[reverse @F]}"' table.txt

# Reverse field order, colon-separated
pperl -F: -lane 'local $" = ":"; print "@{[reverse @F]}"' /etc/passwd

Το @{[ EXPR ]} είναι το ιδίωμα αναφορά-πίνακα-μετά-αποαναφορά που επιτρέπει αυθαίρετες εκφράσεις να παρεμβληθούν σε συμβολοσειρά διπλών εισαγωγικών.

Αναγωγές σε γραμμές#

Το πέρασμα από φίλτρα ανά γραμμή σε υπολογισμό κατά μήκος γραμμών.

Μετρήσεις#

# wc -l
pperl -lne 'END { print $. }' big.txt

# grep -c pattern
pperl -lne '$n++ if /pattern/; END { print $n + 0 }' file

# Count blank lines
pperl -lne '$n++ if /^$/; END { print $n + 0 }' file

# Total fields across the file
pperl -lane '$t += @F; END { print $t }' table.txt

Το ιδίωμα $n + 0 τυπώνει 0 αντί για κενό όταν ο μετρητής δεν αυξήθηκε ποτέ.

Αθροίσματα, ελάχιστα, μέγιστα#

Χρησιμοποιήστε το List::Util μέσω -M.

# Per line
pperl -MList::Util=sum -lane 'print sum @F' data.txt
pperl -MList::Util=min -lane 'print min @F' data.txt
pperl -MList::Util=max -lane 'print max @F' data.txt

# Across all lines
pperl -MList::Util=sum -lane '$s += sum @F; END { print $s }' data.txt
pperl -MList::Util=max -alne '$m = max($m // (), @F); END { print $m }' data.txt

Το $m // () επιστρέφει κενή λίστα όταν το $m είναι απροσδιόριστο, ώστε η πρώτη επανάληψη να μην περάσει undef στο max. Δείτε το numeric για το πλήρες κεφάλαιο αριθμητικής.

Μακρύτερη και βραχύτερη γραμμή#

pperl -ne '$l = $_ if length > length $l; END { print $l }' file
pperl -ne '$s = $_ if $. == 1 || length < length $s; END { print $s }' file

Μοναδικές γραμμές (μόνο πρώτη εμφάνιση)#

pperl -ne 'print unless $seen{$_}++' file

# Or the List::Util one-liner (slurps):
pperl -MList::Util=uniq -e 'print uniq <>' file

Η πρώτη μορφή ροηγείται - η μνήμη κλιμακώνεται με τις διακριτές γραμμές, όχι με τις συνολικές. Η δεύτερη ρουφάει τα πάντα στη μνήμη, μετά εκπέμπει. Προτιμήστε την πρώτη για μεγάλες εισόδους.

Μόνο διπλότυπα#

# Print each duplicate line once, when first seen for the second time
pperl -ne 'print if ++$seen{$_} == 2' file

Φίλτρα παραθύρου περιβάλλοντος#

Εκτύπωση της γραμμής γύρω από μια αντιστοιχία, όχι μόνο της ίδιας της αντιστοιχίας.

# Line immediately before each match (grep -B 1, with caveats)
pperl -ne '/pattern/ && $prev && print $prev; $prev = $_' file

# Line immediately after each match (grep -A 1)
pperl -ne 'print if $p; $p = /pattern/' file

# tail -n 10
pperl -ne 'push @a, $_; shift @a if @a > 10; END { print @a }' file

Για πλούσια συμπεριφορά -A / -B / -C, το grep είναι το σωστό εργαλείο. Τα μονογραμμικά ταιριάζουν όταν ο κανόνας παραθύρου είναι ασυνήθιστος (π.χ. «τύπωσε τη γραμμή που ταιριάζει με X, καθώς και κάθε γραμμή μέχρι την επόμενη κενή γραμμή»).

# Print from /SECTION/ to the next blank line
pperl -ne 'print if /SECTION/ .. /^$/' file

Λειτουργία εγγραφών: -0, -00, -0777#

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

Slurp με -0777#

# Single-shot regex across the whole file
pperl -0777 -ne 'print "match\n" if /BEGIN.*?END/s' text.txt

# Replace only the first occurrence across the file
pperl -0777 -i.bak -pe 's/TODO/DONE/' notes.txt

Το -0777 ορίζει $/ = undef. Όλο το αρχείο έρχεται ως ένα $_. Ο τροποποιητής /s κάνει το . να ταιριάζει με χαρακτήρες αλλαγής γραμμής. Δείτε το regex-recipes για την πλήρη πολυγραμμική εικόνα.

Λειτουργία παραγράφου με -00#

Το -00 ορίζει $/ = "". Κάθε ανάγνωση επιστρέφει τα πάντα μέχρι τον επόμενο οριοθέτη κενής γραμμής.

# Paragraphs containing "TODO"
pperl -00 -ne 'print if /TODO/' notes.md

# Reverse paragraph order
pperl -00 -e 'print reverse <>' notes.md

Εγγραφές οριοθετημένες με NUL μέσω -0#

# Count files produced by find -print0
find . -type f -print0 | pperl -0 -ne '$n++; END { print "$n\n" }'

# Convert NUL-delimited stream to newline-delimited
find . -type f -print0 | pperl -0 -pe 's/\0/\n/'

Επιτόπια επεξεργασία με -i#

Το -i αντικαθιστά κάθε αρχείο εισόδου με ό,τι τυπώνει το -p. Το -i.bak διατηρεί αντίγραφο ασφαλείας.

# Lowercase every occurrence of HOSTNAME in every .conf (keep backup)
pperl -i.bak -pe 's/HOSTNAME/\L$&/g' *.conf

# Delete every line matching DEPRECATED (no backup - only do this
# after you've validated the pattern on one file)
pperl -i -ne 'print unless /DEPRECATED/' file.txt

Τα αρχεία αντιγράφων ασφαλείας συσσωρεύονται. Καθαρίστε τα με rm *.bak αφού επαληθεύσετε. Δείτε το gotchas για τις κλασικές παγίδες επιτόπιας επεξεργασίας.

Δομημένη έξοδος#

Τύπου CSV (ελαφρύ - τα κόμματα δεν εισάγονται σε εισαγωγικά)#

# Rebuild a TSV as CSV (naive, assumes no commas in fields)
pperl -F'\t' -lane 'print join ",", @F' data.tsv

# Add a column of line numbers
pperl -lane 'print join "\t", $., @F' data.tsv

JSON (τυπική βιβλιοθήκη)#

# Emit one JSON object per line (no commas in values assumed)
pperl -MJSON::PP -F: -lane '
    print JSON::PP->new->encode({
        user => $F[0], uid => 0+$F[2], shell => $F[-1]
    })
' /etc/passwd

Τα πολυγραμμικά μονογραμμικά σαν αυτό είναι εκεί που ένα alias αρχίζει να αποδίδει.

Αριθμημένη είσοδος#

pperl -pe '$_ = "$. $_"'                          # 1 gate, 2 apple, ...
pperl -pe 's/^/sprintf "%5d  ", $./e'             # padded width

Ο τροποποιητής /e στο s/// αντιμετωπίζει την αντικατάσταση ως κώδικα Perl. Δείτε το regex-recipes.

Μάθετε περισσότερα#

  • regex-recipes - τα μονογραμμικά που εξαρτώνται από regex: συλλήψεις, διεκδικήσεις γύρω, ονομαστικές ομάδες, /e, /r.

  • numeric - αριθμητική, στατιστική, τυχαία, αριθμητική ημερομηνιών.

  • aliases - μετατρέψτε τις συνταγές που χρησιμοποιείτε εβδομαδιαία σε συναρτήσεις κελύφους.

  • gotchas - εισαγωγικά, κωδικοποίηση, αντίγραφα ασφαλείας -i, εκπλήξεις με τον διαχωριστή εγγραφών.

  • perlop - ο τελεστής flip-flop, ο τελεστής «διαμάντι», s///, tr///, μορφές εισαγωγικών.