# Από 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: ```perl use v5.42; ``` Αυτή η μία γραμμή ενεργοποιεί το `strict`, τα `warnings` και την ενσωματωμένη `say` (μια `print` με τελική νέα γραμμή, ο πρόχειρος δίδυμος του `puts` της Tcl), το σύγχρονο σύνολο χαρακτηριστικών που χρησιμοποιείται παντού. #### NOTE Διακόπτες 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` σήμερα και φέρει την επαληθευμένη έξοδο. Χρησιμοποιήστε τη μορφή πλήρους σεναρίου μέχρι να προστεθούν οι διακόπτες. ## Πώς να το διαβάσετε - [Μεταβλητές και υποκατάσταση]() - το `set` γίνεται `my`, το `[expr]` εξαφανίζεται, η υποκατάσταση `$x` παραμένει. - [Λίστες και πίνακες]() - τα `lindex`/`lappend`/`lsort` γίνονται λειτουργίες πίνακα της Perl. - [Συσχετιστικοί πίνακες και κατακερματισμοί]() - το `set a(k) v` γίνεται `$a{k}`· το `dict` γίνεται κατακερματισμός. - [Procs και αναφορές]() - το `proc` γίνεται `sub`· τα `upvar`/`uplevel` γίνονται αναφορές. - [Regex και αντικατάσταση]() - τα `regexp`/ `regsub`/`string map` γίνονται `m//`/`s///`/`tr///`. - [Ροή ελέγχου]() - τα `if`/`while`/`foreach`/`switch` γίνονται της Perl, συν την παράθεση `{}` έναντι `""`. - [Ο βρόχος γραμμής/εγγραφής]() - ανάγνωση ενός αρχείου γραμμή προς γραμμή με `$_` και `$.`. - [Πεδία και διαχωρισμός]() - `split`/`join`, το αντίστοιχο του `split` της Tcl. - [I/O, σωληνώσεις και επιτόπια επεξεργασία]() - τα `open`/`gets`/`puts`/`exec` γίνονται `open`/`<$fh>`/`print`/`qx`. - [One-liners και διακόπτες]() - `-n`, `-p`, `-e`, σε συντομία. - [Παγίδες ερχόμενοι από την Tcl]() - ρίξτε μια ματιά πριν γράψετε. ## Μεταβλητές και υποκατάσταση Στην Tcl, το `set x 5` δημιουργεί μια μεταβλητή και το `$x` υποκαθιστά την τιμή της. Στην Perl, το `my $x = 5;` δηλώνει μια μεταβλητή με λεξιλογική εμβέλεια και το `$x` την υποκαθιστά - η σύνταξη υποκατάστασης που ήδη ξέρετε μεταφέρεται αυτολεξεί. Η ανακούφιση είναι ότι η Perl έχει εγγενείς χειριστές: δεν υπάρχει `[expr {...}]`. Η αριθμητική είναι απλώς αριθμητική. ```tcl set x 5 set name "world" set sum [expr {$x + 3}] puts "x is $x" puts "sum is $sum" ``` ```perl 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. ```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`. ```perl 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]`. ```tcl 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" } ``` ```perl 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` ως τελευταίο δείκτη: ```perl 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, ή σε μια αναφορά κατακερματισμού όταν χρειάζεται να τον εμφωλεύσετε ή να τον περάσετε τριγύρω. ```tcl 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) ``` ```perl 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) ``` Αυτό εκτυπώνει: ```text 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 και προσθέτουν προεπιλογές. ```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] ``` ```perl 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`. Περνάτε την αναφορά ρητά αντί να ονομάζετε τη μεταβλητή, κάτι που κάνει τη ροή δεδομένων ορατή στο σημείο κλήσης. ```perl 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///` μεταγραμματίζει. ```tcl 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 ``` ```perl 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, και ούτω καθεξής, με τις επώνυμες συλλήψεις να καταλήγουν στο `%+`: ```perl use v5.42; if ("2026-06-21" =~ /(?\d{4})-(?\d{2})/) { say "$+{y} / $+{m}"; # 2026 / 06 } ``` Το `string match` της Tcl είναι ταίριασμα glob, όχι regex (`string match *.txt $name`). Στην Perl, αγκυρώστε ένα regex αντί γι” αυτό - το `/\.txt$/` είναι το αντίστοιχο - επειδή η μία γλώσσα μοτίβων της Perl καλύπτει και τις δύο δουλειές. ```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` λειτουργεί επίσης). ```tcl 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" } ``` ```perl 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`: ```perl 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>)`, με κάθε γραμμή να καταλήγει στο `$_` (την έμμεση μεταβλητή θέματος) ή σε ένα επώνυμο βαθμωτό. Ο αριθμός γραμμής βρίσκεται στο `$.`. ```tcl set fh [open /tmp/tcl_data.txt r] while {[gets $fh line] >= 0} { puts "got: $line" } close $fh ``` ```perl 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`.) Η χρήση του `$_` και του μετρητή γραμμών `$.` διαβάζεται ακόμη πιο κοντά σε έναν βρόχο εγγραφών: ```perl 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*, οπότε παίρνετε όλη τη γλώσσα μοτίβων δωρεάν. ```tcl set line "a:b:c" set parts [split $line ":"] puts [llength $parts] puts [lindex $parts 1] puts [join $parts ","] ``` ```perl 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 ' '` για να ζητάτε λέξεις: ```perl 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` όταν δεν χρειάζεστε την έξοδο. ```tcl set out [exec echo hello from shell] puts "exec said: $out" ``` ```perl 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 ακριβώς αυτού, και το εκτελέσιμο αντίστοιχο πλήρους σεναρίου είναι μια ανάγνωση-τροποποίηση-εγγραφή που μπορείτε να γράψετε σήμερα: ```perl 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 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`. Η εκτελέσιμη μορφή «μέτρησε γραμμές που ταιριάζουν»: ```perl 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](../oneliner/index.md) για τον πλήρη κατάλογο διακοπτών και συνταγές. Η Perl έχει επίσης πλήρεις υπορουτίνες, αναφορές, αρθρώματα και OO αν το σενάριό σας ξεπεράσει μια εργασία συγκόλλησης: τα `namespace eval` και οι κλάσεις `[incr Tcl]` της Tcl αντιστοιχίζονται σε πακέτα της Perl και στη σύγχρονη σύνταξη `class`· δείτε τον [οδηγό Αντικειμενοστραφούς Προγραμματισμού](../oop/index.md) για αυτήν την πλευρά της γλώσσας. ## Παγίδες ερχόμενοι από την 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>) { ... }`, που είναι ακριβώς αυτό στο οποίο αναπτύσσονται οι διακόπτες, μέχρι να προστεθούν.