Από Tcl σε Perl#

Ξέρετε την Tcl. Γράφετε set x 5, υποκαθιστάτε με $x, καταφεύγετε στο [expr {...}] για να κάνετε αριθμητική, χτίζετε λίστες με lappend και τις διατρέχετε με foreach, και λυγίζετε συμβολοσειρές με regexp και regsub. Αυτός ο οδηγός αντιστοιχίζει καθεμία από αυτές τις συνήθειες στην Perl, ώστε να κρατήσετε κάθε αντανακλαστικό που έχετε και να αποκτήσετε τα πράγματα που η Tcl κάνει δύσκολα.

Η Tcl και η Perl μοιράζονται τις ίδιες ρίζες: προγραμματισμό Unix, μια κοσμοθεωρία με προτεραιότητα στη συμβολοσειρά, και την υποκατάσταση με $ ως τον τρόπο που φτάνετε σε μια μεταβλητή. Τα περισσότερα από όσα ξέρετε αντιστοιχίζονται σχεδόν άμεσα - και η Perl σάς δίνει πραγματικές δομές δεδομένων (@arrays και %hashes ως πρωτεύοντες τύπους, όχι λίστες επιστρατευμένες για τον σκοπό) και ένα τεράστιο οικοσύστημα αρθρωμάτων όπου να προσγειωθείτε. Δύο συγκεκριμένα σημεία τριβής παίρνουν το βάρος σε αυτόν τον οδηγό: οι διακριτοί τύποι πίνακα/κατακερματισμού της Perl εκεί που η Tcl έχει λίστες και συσχετιστικούς πίνακες, και το regex της Perl (ένα υπερσύνολο εκείνου της Tcl). Το υλικό γραμμή-τη-φορά και one-liner είναι ελαφρύτερο εδώ, επειδή η Tcl δεν είναι γλώσσα one-liner· θα περάσετε τον χρόνο σας σε μεταβλητές, δεδομένα, ροή ελέγχου και regex.

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 με τελική νέα γραμμή, ο πρόχειρος δίδυμος του puts της Tcl), το σύγχρονο σύνολο χαρακτηριστικών που χρησιμοποιείται παντού.

Σημείωση

Διακόπτες one-liner σε αυτό το build του pperl Οι διακόπτες one-liner της Perl - perl -ne, perl -pe, -a, -i, -l - είναι σωστή perl5 5.42 και είναι η ιδιωματική μορφή για πρόχειρες εργασίες κειμένου. Όμως η οικογένεια διακοπτών έμμεσου βρόχου (-n, -p, -a, -F, -i, -l) δεν αναγνωρίζεται ακόμη από αυτό το build του pperl - μόνο το -e αναγνωρίζεται. Έτσι τα παραδείγματα one-liner παρακάτω εμφανίζονται χωρίς έξοδο, και καθένα συνοδεύεται από μια μορφή πλήρους σεναρίου με ρητό βρόχο (while (<$fh>) { ... }) που όντως τρέχει στο pperl σήμερα και φέρει την επαληθευμένη έξοδο. Χρησιμοποιήστε τη μορφή πλήρους σεναρίου μέχρι να προστεθούν οι διακόπτες.

Πώς να το διαβάσετε#

Μεταβλητές και υποκατάσταση#

Στην Tcl, το set x 5 δημιουργεί μια μεταβλητή και το $x υποκαθιστά την τιμή της. Στην Perl, το my $x = 5; δηλώνει μια μεταβλητή με λεξιλογική εμβέλεια και το $x την υποκαθιστά - η σύνταξη υποκατάστασης που ήδη ξέρετε μεταφέρεται αυτολεξεί. Η ανακούφιση είναι ότι η Perl έχει εγγενείς χειριστές: δεν υπάρχει [expr {...}]. Η αριθμητική είναι απλώς αριθμητική.

set x 5
set name "world"
set sum [expr {$x + 3}]
puts "x is $x"
puts "sum is $sum"
use v5.42;
my $x = 5;                  # set x 5
my $name = "world";
my $sum = $x + 3;           # native operators, no [expr] needed
say "x is $x";              # x is 5
say "sum is $sum";          # sum is 8

Η παράθεση σε εισαγωγικά αντιστοιχίζεται καθαρά, και αυτή είναι μια ευτυχής αντιστοίχιση: το "..." της Tcl (όπου συμβαίνει υποκατάσταση) είναι η συμβολοσειρά σε διπλά εισαγωγικά της Perl, και το {...} της Tcl (κυριολεκτικό, χωρίς υποκατάσταση) είναι η συμβολοσειρά σε μονά εισαγωγικά της Perl.

use v5.42;
my $name = "world";
say "hello, $name";         # hello, world   (interpolates)
say 'no $interp here';      # no $interp here (literal)

Η παγίδα: η Tcl είναι «τα πάντα είναι συμβολοσειρά» και η Perl είναι κοντά σε αυτό - ένα βαθμωτό αυτο-εξαναγκάζεται μεταξύ αριθμού και συμβολοσειράς βάσει περιβάλλοντος - αλλά η Perl χωρίζει τη σύγκριση σε δύο οικογένειες χειριστών, και επιλέγετε βάσει της πράξης, όχι της τιμής. Οι αριθμοί χρησιμοποιούν ==, !=, <, >· οι συμβολοσειρές χρησιμοποιούν eq, ne, lt, gt.

use v5.42;
my $x = "5";
say $x + 3;                 # 8    (numeric context coerces "5")
say $x . "3";               # 53   (string context)
say "10" == "10.0" ? "num-equal" : "num-differ";   # num-equal
say "10" eq "10.0" ? "str-equal" : "str-differ";   # str-differ

Το == συγκρίνει τα "10" και "10.0" ως αριθμούς (ίσα)· το eq τα συγκρίνει ως συμβολοσειρές (διαφορετικά). Η χρήση του == εκεί που εννοούσατε eq, ή το αντίστροφο, είναι το ένα σιωπηλό σφάλμα για το οποίο σας προετοιμάζει η κοσμοθεωρία με προτεραιότητα στη συμβολοσειρά.

Λίστες και πίνακες#

Μια λίστα της Tcl είναι ένας πίνακας της Perl, και τα ρήματα ταιριάζουν ένα προς ένα. Η μεγάλη μετατόπιση: στην Tcl τα πάντα είναι λίστα, συμπεριλαμβανομένων των συμβολοσειρών που διαχωρίζετε στο λεπτό· στην Perl ένας πίνακας (@a) είναι ένας διακριτός, πρωτεύων τύπος με το δικό του sigil. Όταν φτάνετε σε ένα στοιχείο, το sigil ακολουθεί το στοιχείο, οπότε είναι $a[0] (ένα βαθμωτό), όχι @a[0].

set items [list apple pear fig]
puts [lindex $items 0]
puts [llength $items]
lappend items plum
set sorted [lsort $items]
foreach it $items { puts "item: $it" }
use v5.42;
my @items = ("apple", "pear", "fig");
say $items[0];                  # apple        (lindex $items 0)
say scalar @items;              # 3            (llength $items)
push @items, "plum";            # lappend items plum
my @sorted = sort @items;       # lsort
say "@sorted";                  # apple fig pear plum
for my $it (@items) {           # foreach it $items
    say "item: $it";
}

Το lsearch - «βρες τον δείκτη ενός στοιχείου που ταιριάζει» - δεν έχει μία ενσωματωμένη συνάρτηση· η ιδιωματική Perl είναι το grep πάνω στο εύρος δεικτών, με το $#items ως τελευταίο δείκτη:

use v5.42;
my @items = ("apple", "pear", "fig", "plum");
my ($idx) = grep { $items[$_] eq "fig" } 0 .. $#items;   # lsearch
say "fig at $idx";              # fig at 2

Η παγίδα: το scalar @items είναι ο τρόπος που παίρνετε το μήκος (το llength της Tcl)· γράφοντας my $n = @items λειτουργεί επειδή η ανάθεση ενός πίνακα σε βαθμωτό δίνει το πλήθος του, αλλά γράψτε το scalar @items όταν θέλετε το μήκος μέσα σε μια μεγαλύτερη έκφραση. Και το sort συγκρίνει ως συμβολοσειρές εξ ορισμού, οπότε το sort (10, 9, 100) δίνει 10 100 9· δώστε έναν αριθμητικό συγκριτή sort { $a <=> $b } @nums για αριθμητική σειρά, όπου τα $a και $b είναι τα δύο στοιχεία και το <=> είναι ο αριθμητικός τριαδικός χειριστής.

Συσχετιστικοί πίνακες και κατακερματισμοί#

Ένας συσχετιστικός πίνακας της Tcl - set a(red) 1 - είναι ένας κατακερματισμός της Perl. Η πρόσβαση στα στοιχεία αντιστοιχίζεται άμεσα: το $a(red) της Tcl είναι το $a{red} της Perl, και ολόκληρη η συλλογή είναι %a (η Tcl δεν έχει σύνταξη για τον πίνακα ως μία τιμή· η Perl έχει). Το dict της σύγχρονης Tcl αντιστοιχίζεται στον ίδιο κατακερματισμό της Perl, ή σε μια αναφορά κατακερματισμού όταν χρειάζεται να τον εμφωλεύσετε ή να τον περάσετε τριγύρω.

set a(red) 1
set a(green) 2
set a(blue) 3
puts $a(red)
puts [array exists a]
foreach k [lsort [array names a]] { puts "$k => $a($k)" }
unset a(blue)
use v5.42;
my %a = (red => 1, green => 2, blue => 3);
say $a{red};                            # 1     ($a(red))
say exists $a{green} ? "yes" : "no";    # yes   (info exists a(green))
for my $k (sort keys %a) {              # array names a
    say "$k => $a{$k}";
}
delete $a{blue};                        # unset a(blue)

Αυτό εκτυπώνει:

1
yes
red => 1
green => 2
blue => 3

Η παγίδα: η ιδιότητα μέλους είναι exists $a{key}, όχι μια ξεχωριστή εντολή, και το παχύ κόμμα => είναι ο ιδιωματικός διαχωριστής κλειδιού/τιμής σε ένα κυριολεκτικό κατακερματισμού. Το => επίσης αυτο-θέτει σε εισαγωγικά τη bareword στα αριστερά του, οπότε το red => 1 δεν χρειάζεται εισαγωγικά γύρω από το red. Ένας κατακερματισμός δεν έχει εγγενή σειρά (ούτε ένας πίνακας της Tcl)· επαναλαμβάνετε με sort keys %a όταν θέλετε μια σταθερή, ακριβώς όπως καταφεύγετε στο lsort [array names a].

Procs και αναφορές#

Το proc name {args} {body} γίνεται το sub name { ... } της Perl. Ο κλασικός τρόπος της Tcl να διαβάζετε ορίσματα - θεσιακά, κατ” όνομα - έχει έναν άμεσο δίδυμο στην Perl: το my ($a, $b) = @_; αποσυσκευάζει τον πίνακα ορισμάτων @_. Η σύγχρονη Perl έχει επίσης υπογραφές, που διαβάζονται σαν τη λίστα {args} της Tcl και προσθέτουν προεπιλογές.

proc add {a b} {
    return [expr {$a + $b}]
}
puts [add 3 4]

proc greet {who {greeting Hello}} {
    return "$greeting, $who!"
}
puts [greet Tcl]
puts [greet Perl Hi]
use v5.42;
sub add {
    my ($a, $b) = @_;       # unpack the argument array
    return $a + $b;
}
say add(3, 4);              # 7

sub greet ($who, $greeting = "Hello") {   # signature with default
    return "$greeting, $who!";
}
say greet("Tcl");           # Hello, Tcl!
say greet("Perl", "Hi");    # Hi, Perl!

Το πέρασμα-κατ”-όνομα της Tcl - το upvar, όπου ένα proc φτάνει προς τα πάνω και μεταλλάσσει μια μεταβλητή του καλούντος - γίνεται μια αναφορά της Perl: πάρτε μία με \, ακολουθήστε την με $$ref. Περνάτε την αναφορά ρητά αντί να ονομάζετε τη μεταβλητή, κάτι που κάνει τη ροή δεδομένων ορατή στο σημείο κλήσης.

use v5.42;
sub increment {
    my ($ref) = @_;
    $$ref++;                # mutate through the reference (Tcl: upvar)
}
my $count = 10;
increment(\$count);         # pass a reference to $count
say $count;                 # 11

Η παγίδα: το @_ είναι ο πίνακας ορισμάτων, και το my ($a, $b) = @_; αντιγράφει τα ορίσματα σε επώνυμες τοπικές μεταβλητές - η γραμμή που σχεδόν πάντα θέλετε στην αρχή μιας υπορουτίνας. Η καταφυγή σε ψευδωνυμοποίηση τύπου upvar σπάνια χρειάζεται στην Perl· όταν όντως χρειάζεται να μεταλλάξετε δεδομένα του καλούντος, περάστε μια αναφορά (\$x, \@arr, \%h) σκόπιμα αντί να ψευδωνυμίζετε κατ” όνομα. Οι αναφορές είναι επίσης ο τρόπος που η Perl εμφωλεύει δεδομένα (έναν πίνακα κατακερματισμών, έναν κατακερματισμό πινάκων)· ο ίδιος μηχανισμός που αντικαθιστά το upvar είναι αυτός που αντικαθιστά τις εμφωλευμένες λίστες κωδικοποιημένες σε συμβολοσειρά της Tcl.

Regex και αντικατάσταση#

Αυτή είναι μια ουσιαστική ενότητα. Τα regexp και regsub της Tcl χρησιμοποιούν Προηγμένες Κανονικές Εκφράσεις· το regex της Perl είναι ένα υπερσύνολο, οπότε τα μοτίβα που ξέρετε μεταφέρονται και κερδίζουν χαρακτηριστικά. Η Perl κάνει το regex σύνταξη, όχι εντολή: το =~ δένει ένα μοτίβο σε μια συμβολοσειρά, το m// ταιριάζει, το s/// αντικαθιστά, και το tr/// μεταγραμματίζει.

set s "order 42 shipped"
if {[regexp {(\d+)} $s -> num]} {
    puts "number: $num"
}
set t [regsub -all {o} "foo boo zoo" O]
puts $t
set u [string map {a A b B} "abcabc"]
puts $u
use v5.42;
my $s = "order 42 shipped";
if ($s =~ /(\d+)/) {            # regexp; capture lands in $1
    say "number: $1";          # number: 42
}
(my $t = "foo boo zoo") =~ s/o/O/g;    # regsub -all  ->  s///g
say $t;                                # fOO bOO zOO
(my $u = "abcabc") =~ tr/ab/AB/;       # string map (char-for-char)
say $u;                                # ABcABc

Και η σύλληψη αντιστοιχίζεται: η μεταβλητή αντιστοιχίας -> num της Tcl γίνεται τα $1, $2 της Perl, και ούτω καθεξής, με τις επώνυμες συλλήψεις να καταλήγουν στο %+:

use v5.42;
if ("2026-06-21" =~ /(?<y>\d{4})-(?<m>\d{2})/) {
    say "$+{y} / $+{m}";        # 2026 / 06
}

Το string match της Tcl είναι ταίριασμα glob, όχι regex (string match *.txt $name). Στην Perl, αγκυρώστε ένα regex αντί γι” αυτό - το /\.txt$/ είναι το αντίστοιχο - επειδή η μία γλώσσα μοτίβων της Perl καλύπτει και τις δύο δουλειές.

use v5.42;
my $name = "report.txt";
say "matches" if $name =~ /\.txt$/;     # string match *.txt $name
# matches

Η παγίδα: το s/// τροποποιεί τον στόχο του επιτόπια και επιστρέφει το πλήθος των αντικαταστάσεων, όχι τη νέα συμβολοσειρά - γι” αυτό τα παραπάνω παραδείγματα αντιγράφουν πρώτα με (my $t = "...") πριν αντικαταστήσουν. Για να πάρετε μια νέα συμβολοσειρά και να αφήσετε το πρωτότυπο ανέγγιχτο, χρησιμοποιήστε τη σημαία /r: my $new = $s =~ s/o/O/gr. Και το tr/// (το αντίστοιχο του string map για μεμονωμένους χαρακτήρες) δεν είναι regex: η αριστερή του πλευρά είναι ένα κυριολεκτικό σύνολο χαρακτήρων, οπότε το tr/ab/AB/ αντιστοιχίζει μόνο τα a και b. Για εργασία με μοτίβα, καταφύγετε στο s///.

Ροή ελέγχου#

Οι δομές ελέγχου αντιστοιχίζονται σχεδόν μία προς μία· η γραφή αλλάζει και τα άγκιστρα μένουν. Το if {cond} {body} της Tcl γίνεται το if (cond) { body } της Perl, το elseif γίνεται elsif, και το foreach γίνεται for (οι δύο γραφές είναι ψευδώνυμα στην Perl· το foreach λειτουργεί επίσης).

if {$n < 0} {
    set sign neg
} elseif {$n == 0} {
    set sign zero
} else {
    set sign pos
}

set i 0
while {$i < 3} { puts "i=$i"; incr i }

foreach w {a b c} { puts "w=$w" }
use v5.42;
my $n = 0;
my $sign;
if    ($n < 0)  { $sign = "neg"  }
elsif ($n == 0) { $sign = "zero" }   # elseif -> elsif
else            { $sign = "pos"  }
say $sign;                  # zero

my $i = 0;
while ($i < 3) { say "i=$i"; $i++ }  # incr i -> $i++

for my $w (qw(a b c)) { say "w=$w" } # foreach w {a b c}

Το switch της Tcl δεν έχει μία δεσμευμένη λέξη στην Perl· η ιδιωματική αντικατάσταση είναι ένας κατακερματισμός αποστολής που αντιστοιχίζει κάθε περίπτωση σε μια αναφορά κώδικα, που είναι ταχύτερος και πιο ευέλικτος από μια αλυσίδα if:

use v5.42;
my $cmd = "start";
my %dispatch = (
    start => sub { "starting" },
    stop  => sub { "stopping" },
);
say $dispatch{$cmd}->();     # starting

Η παγίδα: η διάκριση {} έναντι "" στην οποία βασίζεστε στην Tcl για αναβολή έναντι υποκατάστασης αντιστοιχίζεται στα '' έναντι "" της Perl για συμβολοσειρές (που καλύφθηκαν παραπάνω), αλλά τα άγκιστρα μπλοκ της Perl δεν είναι παράθεση - ένα { ... } της Perl μετά από if/while/for είναι ένα μπλοκ κώδικα, πάντα αποτιμώμενο, ποτέ μια αναβληθείσα συμβολοσειρά. Δεν υπάρχει βήμα «το σώμα είναι συμβολοσειρά μέχρι να το τρέξω»· η Perl αναλύει το μπλοκ κατά τη μεταγλώττιση. Οι μεταθεματικοί τροποποιητές είναι ένα μπόνους για το οποίο η Tcl δεν έχει μορφή: τα say $_ for @items; και say "neg" if $n < 0; φέρουν τον βρόχο ή τη συνθήκη μετά την εντολή.

Ο βρόχος γραμμής/εγγραφής#

Η Tcl διαβάζει ένα αρχείο με set fh [open f r]; while {[gets $fh line] >= 0} {...}. Το αντίστοιχο της Perl είναι ένας βρόχος while (<$fh>), με κάθε γραμμή να καταλήγει στο $_ (την έμμεση μεταβλητή θέματος) ή σε ένα επώνυμο βαθμωτό. Ο αριθμός γραμμής βρίσκεται στο $..

set fh [open /tmp/tcl_data.txt r]
while {[gets $fh line] >= 0} {
    puts "got: $line"
}
close $fh
use v5.42;
open my $fh, '<', '/tmp/tcl_data.txt' or die "open: $!";
while (my $line = <$fh>) {       # gets $fh line
    chomp $line;                 # <$fh> keeps the newline; strip it
    say "got: $line";            # puts
}
close $fh;
# got: apple
# got: banana
# got: cherry

(Το αρχείο εισόδου περιείχε apple, banana, cherry.) Η χρήση του $_ και του μετρητή γραμμών $. διαβάζεται ακόμη πιο κοντά σε έναν βρόχο εγγραφών:

use v5.42;
open my $fh, '<', '/tmp/tcl_data.txt' or die "open: $!";
while (<$fh>) {                  # each line lands in $_
    chomp;                       # chomp defaults to $_
    say "$. : $_";              # $. is the current line number
}
close $fh;
# 1 : apple
# 2 : banana
# 3 : cherry

Η παγίδα: το gets της Tcl αφαιρεί την τελική νέα γραμμή για εσάς· το <$fh> της Perl την κρατά, οπότε καλέστε chomp όταν δεν τη θέλετε. Χωρίς όρισμα, τα chomp και say/print έχουν αμφότερα προεπιλογή το $_, γι” αυτό ο δεύτερος βρόχος ποτέ δεν ονομάζει τη μεταβλητή της γραμμής.

Πεδία και διαχωρισμός#

Το split $line $sep της Tcl επιστρέφει μια λίστα· το split /sep/, $line της Perl επιστρέφει έναν πίνακα, και το join το ξανασυναρμολογεί. Η διαφορά: ένας διαχωριστής split της Perl είναι ένα regex, οπότε παίρνετε όλη τη γλώσσα μοτίβων δωρεάν.

set line "a:b:c"
set parts [split $line ":"]
puts [llength $parts]
puts [lindex $parts 1]
puts [join $parts ","]
use v5.42;
my $line = "a:b:c";
my @parts = split /:/, $line;   # split $line ":"  (separator is a regex)
say scalar @parts;              # 3        (llength $parts)
say $parts[1];                  # b        (lindex $parts 1)
say join ",", @parts;           # a,b,c    (join $parts ",")

Η παγίδα: το split ' ' με μια κυριολεκτική συμβολοσειρά ενός κενού είναι μια ειδική περίπτωση που διαχωρίζει σε οποιαδήποτε διαδοχή κενών χαρακτήρων και απορρίπτει τα αρχικά κενά πεδία - η συμπεριφορά τύπου awk «διαχώρισε σε λέξεις», και συνήθως αυτό που θέλετε για ελεύθερης μορφής είσοδο. Το split / / (ένα regex με ένα κενό) είναι το κυριολεκτικό «διαχώρισε σε κάθε μεμονωμένο κενό» και δεν συμπτύσσει διαδοχές. Καταφύγετε στο split ' ' για να ζητάτε λέξεις:

use v5.42;
my @words = split ' ', "  the  quick brown  ";
say "@words";                   # the quick brown

I/O, σωληνώσεις και επιτόπια επεξεργασία#

Τα open/gets/puts/read/close της Tcl αντιστοιχίζονται στα open/<$fh>/ print/slurp/close της Perl. Το ιδίωμα είναι το open τριών ορισμάτων με έναν λεξιλογικό περιγραφέα. Το exec της Tcl - τρέξε μια εντολή και σύλλαβε την έξοδό της - γίνεται το qx{...} (backticks) της Perl ή system όταν δεν χρειάζεστε την έξοδο.

set out [exec echo hello from shell]
puts "exec said: $out"
use v5.42;
my $out = qx{echo hello from shell};    # exec  ->  qx// (backticks)
chomp $out;
say "exec said: $out";                  # exec said: hello from shell

Η Tcl δεν έχει ενσωματωμένη επιτόπια επεξεργασία αρχείων· διαβάζετε, μετασχηματίζετε και γράφετε πίσω. Ο διακόπτης -i της Perl είναι η μορφή one-liner ακριβώς αυτού, και το εκτελέσιμο αντίστοιχο πλήρους σεναρίου είναι μια ανάγνωση-τροποποίηση-εγγραφή που μπορείτε να γράψετε σήμερα:

use v5.42;
my $path = '/tmp/tcl_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 επιστρέφει ψευδές σε αποτυχία αντί να εγείρει σφάλμα (η Tcl εκτοξεύει ένα σφάλμα που πιάνετε με catch), οπότε το ιδίωμα or die "...: $!" είναι υποχρεωτικό - το $! είναι η συμβολοσειρά σφάλματος του συστήματος. Για σωληνώσεις, η Perl ανοίγει έναν περιγραφέα σωλήνωσης απευθείας: το open my $fh, '-|', 'ls', '-l' διαβάζει την έξοδο μιας εντολής και το open my $fh, '|-', 'sort' γράφει στην είσοδο μιας εντολής, η δομημένη μορφή του open "|command" της Tcl.

One-liners και διακόπτες#

Η Tcl δεν είναι γλώσσα one-liner, οπότε αυτή η ενότητα είναι σύντομη - αλλά η Perl είναι, και μόλις αφήσετε την Tcl πίσω αξίζει να ξέρετε ότι το αντανακλαστικό υπάρχει. Η οικογένεια διακοπτών: το -e παρέχει το πρόγραμμα, το -n το τυλίγει σε έναν βρόχο χωρίς αυτόματη εκτύπωση, το -p το τυλίγει σε έναν βρόχο με αυτόματη εκτύπωση, το -i επεξεργάζεται επιτόπια, και τα -a/-F αυτοδιαχωρίζουν κάθε γραμμή σε @F. Τα μπλοκ BEGIN { } και END { } τρέχουν πριν και μετά τον βρόχο.

perl -ne 'print if /error/' log.txt        # print matching lines
perl -pe 's/\d+/N/g' input.txt             # mask numbers
perl -nE 'END { say $n } $n++ if /error/' log.txt   # count, END block

Αυτά εμφανίζονται χωρίς έξοδο επειδή οι διακόπτες έμμεσου βρόχου δεν αναγνωρίζονται ακόμη από αυτό το build του pperl (δείτε τη σημείωση στην αρχή). Καθένας αντιστοιχίζεται σε μια επαληθευμένη μορφή ρητού βρόχου: το perl -ne 'CODE' είναι while (<$fh>) { CODE }, και το perl -pe 'CODE' είναι το ίδιο με μια τελική print. Η εκτελέσιμη μορφή «μέτρησε γραμμές που ταιριάζουν»:

use v5.42;
open my $fh, '<', '/tmp/tcl_data.txt' or die "open: $!";
my $n = 0;
while (<$fh>) {
    $n++ if /banana/;          # the body of -ne
}
say $n;                        # 1

Η παγίδα: μέχρι να προστεθούν οι διακόπτες στο pperl, γράψτε τον ρητό βρόχο (τρέχει σήμερα και είναι ούτως ή άλλως αυτό στο οποίο αναπτύσσονται οι διακόπτες), και συμβουλευτείτε τον οδηγό One-Liners για τον πλήρη κατάλογο διακοπτών και συνταγές. Η Perl έχει επίσης πλήρεις υπορουτίνες, αναφορές, αρθρώματα και OO αν το σενάριό σας ξεπεράσει μια εργασία συγκόλλησης: τα namespace eval και οι κλάσεις [incr Tcl] της Tcl αντιστοιχίζονται σε πακέτα της Perl και στη σύγχρονη σύνταξη class· δείτε τον οδηγό Αντικειμενοστραφούς Προγραμματισμού για αυτήν την πλευρά της γλώσσας.

Παγίδες ερχόμενοι από την Tcl#

Οι παγίδες, συγκεντρωμένες για μια τελική ματιά πριν γράψετε:

  • Δύο οικογένειες σύγκρισης. Τα ==/</<=> συγκρίνουν αριθμητικά· τα eq/lt/cmp συγκρίνουν ως συμβολοσειρές. Το "10" == "10.0" είναι αληθές, το "10" eq "10.0" είναι ψευδές. Επιλέξτε βάσει της πράξης, όχι της τιμής - το ένα σιωπηλό σφάλμα που προσκαλεί η κοσμοθεωρία με προτεραιότητα στη συμβολοσειρά.

  • Το sigil ακολουθεί το στοιχείο. Ένα στοιχείο του @items είναι $items[0] (ένα βαθμωτό), όχι @items[0]· μία τιμή του %a είναι $a{red}. Το sigil του περιέκτη και το sigil του στοιχείου διαφέρουν.

  • Το sort ταξινομεί ως συμβολοσειρές εξ ορισμού, όπως η σύγκριση με eq. Δώστε { $a <=> $b } για αριθμητική σειρά.

  • Το s/// επιστρέφει ένα πλήθος, όχι τη νέα συμβολοσειρά, και επεξεργάζεται επιτόπια. Αντιγράψτε πρώτα ((my $t = $s) =~ s/.../.../) ή χρησιμοποιήστε τη σημαία /r για μια φρέσκια συμβολοσειρά.

  • Το tr/// (το αντίστοιχο του string map) είναι ένα κυριολεκτικό σύνολο χαρακτήρων, όχι regex. Το tr/ab/AB/ αντιστοιχίζει μεμονωμένους χαρακτήρες. Για μοτίβα, χρησιμοποιήστε s///.

  • Τα split ' ' και split / / διαφέρουν. Η συμβολοσειρά κυριολεκτικού κενού διαχωρίζει σε διαδοχές κενών χαρακτήρων και απορρίπτει τα αρχικά κενά (ο tokeniser λέξεων)· το regex ενός κενού όχι. Χρησιμοποιήστε split ' ' για ελεύθερης μορφής είσοδο.

  • Το <$fh> κρατά την τελική νέα γραμμή, σε αντίθεση με το gets της Tcl. Καλέστε chomp για να την αφαιρέσετε.

  • Η open δεν εγείρει σφάλμα σε αποτυχία. Χρησιμοποιήστε open my $fh, '<', $path or die "...: $!". Το $! είναι η συμβολοσειρά σφάλματος του συστήματος· δεν υπάρχει catch να το τυλίξει.

  • Οι αναφορές αντικαθιστούν το upvar. Για να μεταλλάξετε μια μεταβλητή του καλούντος, περάστε μια αναφορά (\$x, \@arr, \%h) σκόπιμα αντί να ψευδωνυμίζετε κατ” όνομα. Οι αναφορές είναι επίσης ο τρόπος που η Perl εμφωλεύει δεδομένα.

  • Ένα μπλοκ { ... } είναι κώδικας, όχι αναβληθείσα συμβολοσειρά. Η Perl αναλύει τα μπλοκ κατά τη μεταγλώττιση· δεν υπάρχει βήμα «το σώμα είναι συμβολοσειρά μέχρι να το τρέξω». Μόνο τα ''/"" φέρουν τη διάκριση υποκατάστασης {}/"" της Tcl.

  • Οι διακόπτες έμμεσου βρόχου (-n/-p/-a/-F/-i/-l) δεν αναγνωρίζονται ακόμη από αυτό το build του pperl. Μόνο το -e λειτουργεί σήμερα. Γράψτε τον ρητό βρόχο while (<$fh>) { ... }, που είναι ακριβώς αυτό στο οποίο αναπτύσσονται οι διακόπτες, μέχρι να προστεθούν.