# Από Shell σε Perl Ξέρετε το κέλυφος. Κολλάτε προγράμματα μεταξύ τους με σωληνώσεις, καταφεύγετε στα `sed`, `awk`, `grep` και `cut` σε μια σωλήνωση χωρίς σκέψη, συλλαμβάνετε την έξοδο εντολών με `$(...)`, και προγραμματίζετε ροή ελέγχου με `for f in *`, `while read line` και `case`. Αυτός ο οδηγός αντιστοιχίζει καθεμία από αυτές τις συνήθειες στην Perl, ώστε να κρατήσετε τα αντανακλαστικά σωλήνωσης και να αποκτήσετε τα πράγματα που το κέλυφος κάνει επώδυνα. Όταν ένα σενάριο κελύφους μεγαλώσει πέρα από περίπου 50 γραμμές παράθεσης σε εισαγωγικά και σωληνώσεων `sed`/`awk`/`grep`, η Perl είναι το φυσικό επόμενο βήμα: τα κάνει όλα σε μία γλώσσα, με πραγματικές δομές δεδομένων αντί για συμβολοσειρές οριοθετημένες με κενά. Το πλαίσιο που πρέπει να κρατήσετε: **η Perl είναι η σωλήνωση κελύφους, αλλά η γλώσσα του φίλτρου είναι μια πραγματική γλώσσα.** Εξακολουθείτε να κάνετε `open` σε σωληνώσεις, εξακολουθείτε να κάνετε glob, εξακολουθείτε να τρέχετε εντολές και να διαβάζετε την έξοδό τους. Αυτό που αλλάζει είναι ότι ανάμεσα στις σωληνώσεις έχετε τώρα `@arrays`, `%hashes`, πραγματικό regex, και αριθμητική που δεν χρειάζεται `$(( ))`. Ο ένας τύπος δεδομένων του κελύφους είναι η συμβολοσειρά· η Perl σάς δίνει πραγματικούς περιέκτες. 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` με τελική νέα γραμμή), το σύγχρονο σύνολο χαρακτηριστικών που χρησιμοποιείται παντού. #### NOTE Διακόπτες one-liner σε αυτό το build του pperl Ο φυσικός δίδυμος του προγραμματιστή κελύφους στην Perl είναι το one-liner: `perl -ne` και `perl -pe`, το φίλτρο μέσα στη σωλήνωση. Αυτοί οι διακόπτες είναι **σωστή perl5 5.42** και εμφανίζονται σε όλον αυτόν τον οδηγό ως η ιδιωματική μορφή. Όμως η οικογένεια διακοπτών έμμεσου βρόχου (`-n`, `-p`, `-a`, `-F`, `-i`, `-l`) **δεν αναγνωρίζεται ακόμη από αυτό το build του `pperl`** - μόνο το `-e` αναγνωρίζεται. Έτσι τα παραδείγματα one-liner παρακάτω εμφανίζονται *χωρίς* έξοδο, και καθένα συνοδεύεται από μια μορφή πλήρους σεναρίου με ρητό βρόχο (`while (<$fh>) { ... }`) που **όντως** τρέχει στο `pperl` σήμερα και φέρει την επαληθευμένη έξοδο. Χρησιμοποιήστε τη μορφή πλήρους σεναρίου μέχρι να προστεθούν οι διακόπτες. ## Πώς να το διαβάσετε - [Ο βρόχος εγγραφών]() - το `while read line` γίνεται `while (<$fh>)` και `$_`. - [Πεδία και διαχωρισμός]() - τα πεδία `cut`/`IFS`/`awk` γίνονται `split` και ένας πραγματικός πίνακας. - [Regex και αντικατάσταση]() - οι παραμετρικές αναπτύξεις `${var#...}`/`${var/a/b}` του κελύφους γίνονται πραγματικό regex. - [Διευθύνσεις και εύρη]() - `grep -n`, `awk NR==2` και εύρη γραμμών. - [I/O, σωληνώσεις και επιτόπια επεξεργασία]() - η καρδιά: `open`, `-|`/`|-`, ανακατεύθυνση, here-docs, `$(...)`. - [One-liners και διακόπτες]() - `-n`, `-p`, `-e`, `BEGIN`/`END`. - [Ροή ελέγχου]() - `for`/`while`/`case`/`if`, έλεγχοι αρχείων, κατάσταση εξόδου. - [Μεταβλητές και δεδομένα]() - το `$var` γίνεται `my $var`, συν τους `@arrays` και `%hashes` που το κέλυφος ποτέ δεν είχε. - [Παγίδες ερχόμενοι από το κέλυφος]() - ρίξτε μια ματιά πριν γράψετε. ## Ο βρόχος εγγραφών Το ιδίωμα γραμμή-τη-φορά του κελύφους είναι `while read line; do ... done`, που διαβάζει μία γραμμή ανά επανάληψη στο `$line` (και την περικόπτει σύμφωνα με το `IFS`). Το αντίστοιχο της Perl είναι `while (<$fh>)`, που διαβάζει μία γραμμή ανά επανάληψη στο `$_`, την έμμεση μεταβλητή θέματος. Η κρίσιμη διαφορά: η Perl κρατά την τελική νέα γραμμή, οπότε κάνετε εσείς `chomp`, ακριβώς εκεί όπου το `read` του κελύφους θα την είχε καταπιεί. ```bash while read line; do echo "got: $line" done < data.txt ``` ```perl use v5.42; open my $fh, '<', '/tmp/data.txt' or die "open: $!"; while (my $line = <$fh>) { # each line, with its newline chomp $line; # strip it, like read does say "got: $line"; } close $fh; # got: apple # got: banana # got: cherry ``` (Το αρχείο εισόδου περιείχε `apple`, `banana`, `cherry`.) Διαβάστε με το γυμνό `<$fh>` και η γραμμή καταλήγει στο `$_`, την προεπιλογή στην οποία λειτουργούν οι περισσότερες ενσωματωμένες συναρτήσεις γραμμών. Ο αριθμός γραμμής βρίσκεται στο `$.`. Αυτή είναι η μορφή στην οποία καταφεύγετε όταν μεταφράζετε ένα φίλτρο: ```perl use v5.42; open my $fh, '<', '/tmp/data.txt' or die "open: $!"; while (<$fh>) { # line lands in $_ chomp; # chomp $_ by default say "$. : $_"; # $. is the line number } close $fh; # 1 : apple # 2 : banana # 3 : cherry ``` Η παγίδα: το `read` διαχωρίζει βάσει του `IFS` και περικόπτει· το `<$fh>` δεν κάνει κανένα από τα δύο. Μια ανάγνωση γραμμής στην Perl είναι όλη η ακατέργαστη γραμμή συμπεριλαμβανομένου του `\n`, οπότε το `chomp` είναι το αντανακλαστικό σας, και ο διαχωρισμός πεδίων είναι ένα ξεχωριστό, ρητό βήμα (η επόμενη ενότητα). Ό,τι χάνετε στην αυτόματη περικοπή το κερδίζετε στο να μην παραμορφώνει σιωπηλά το `IFS` τα δεδομένα σας. ## Πεδία και διαχωρισμός Στο κέλυφος φτάνετε στα πεδία με `cut -d: -f1`, με `awk '{print $1}'`, ή ορίζοντας το `IFS` και αφήνοντας το `read` να διαχωρίσει για εσάς. Η μία απάντηση της Perl είναι το `split`: δώστε του έναν διαχωριστή και μια συμβολοσειρά, πάρτε πίσω έναν πραγματικό πίνακα. Τα θεσιακά πεδία που το κέλυφος αριθμεί `$1`, `$2` γίνονται στοιχεία πίνακα `$f[0]`, `$f[1]` - **μηδενοβάσει**, σε αντίθεση με το βάσει-του-ένα `$1` του `awk`. ```bash line='root:x:0:0:root:/root:/bin/bash' user=$(echo "$line" | cut -d: -f1) shell=$(echo "$line" | cut -d: -f7) echo "$user $shell" ``` ```perl use v5.42; my $line = "root:x:0:0:root:/root:/bin/bash"; my @f = split /:/, $line; say "user: $f[0]"; # user: root say "shell: $f[-1]"; # shell: /bin/bash (negative index) say "fields: ", scalar @f; # fields: 7 ``` Για να διαχωρίσετε σε διαδοχές κενών χαρακτήρων - τον προεπιλεγμένο διαχωρισμό λέξεων του κελύφους, και την προεπιλογή του `awk` - χρησιμοποιήστε το ειδικό μοτίβο `split ' '` (μια κυριολεκτική συμβολοσειρά ενός κενού, που επίσης παραλείπει τα αρχικά κενά). Για να ενώσετε ξανά τα πεδία, `join`: ```perl use v5.42; my @words = split ' ', " the quick brown "; say scalar @words; # 3 (leading/inner blanks collapsed) say join "|", @words; # the|quick|brown ``` Η παγίδα: το `split /:/` με ένα κυριολεκτικό μοτίβο κρατά κενά τελικά πεδία μόνο μέχρι ένα σημείο - εξ ορισμού η Perl απορρίπτει τα κενά τελικά πεδία, οπότε το `split /:/, "a::"` δίνει `("a")`, όχι `("a", "", "")`. Δώστε ένα αρνητικό όριο (`split /:/, $s, -1`) για να τα κρατήσετε, το αντίστοιχο του να ενδιαφέρεστε για τα κενά τελικά πεδία του `cut`. Και το `split ' '` (η μαγική μορφή με κενά) **δεν** είναι το ίδιο με το `split / /` (ένα μοναδικό κυριολεκτικό κενό): η πρώτη συμπτύσσει διαδοχές και περικόπτει, η δεύτερη όχι. ## Regex και αντικατάσταση Οι παραμετρικές αναπτύξεις `${}` του κελύφους γίνονται πραγματικό regex - και αυτό είναι μια μεγάλη αναβάθμιση. Τα `${var#prefix}`, `${var%suffix}`, `${var/a/b}` και `${var//a/b}` είναι το καθένα μια ειδικού σκοπού, περιορισμένη επεξεργασία συμβολοσειράς. Η Perl αντικαθιστά ολόκληρη την οικογένεια με έναν χειριστή, το `s///`, που δέχεται μια πραγματική κανονική έκφραση και το πλήρες σύνολο σημαιών. ```bash f='report.txt.bak' base=${f%.bak} # strip suffix path='/usr/local/bin' tail=${path##*/} # basename dir=${path%/*} # dirname s='a-b-c' one=${s/-/_} # replace first all=${s//-/_} # replace all ``` ```perl use v5.42; my $f = "report.txt.bak"; (my $base = $f) =~ s/\.bak$//; # ${f%.bak} say $base; # report.txt my $path = "/usr/local/bin"; (my $tail = $path) =~ s{.*/}{}; # ${path##*/} basename say $tail; # bin (my $dir = $path) =~ s{/[^/]*$}{}; # ${path%/*} dirname say $dir; # /usr/local my $s = "a-b-c"; (my $one = $s) =~ s/-/_/; # ${s/-/_} first only say $one; # a_b-c (my $all = $s) =~ s/-/_/g; # ${s//-/_} /g = global say $all; # a_b_c ``` Επειδή είναι ένα πραγματικό regex, τα πράγματα που το κέλυφος δεν μπορεί να κάνει καθόλου είναι τετριμμένα: οι ομάδες σύλληψης καταλήγουν στα `$1`, `$2`· η σημαία `/e` εκτελεί κώδικα Perl στην αντικατάσταση· η σημαία `/r` επιστρέφει ένα αντίγραφο αντί για επιτόπια επεξεργασία· και τα `/i`, `/x` τροποποιούν το ταίριασμα. ```perl 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 my $date = "2026-06-21"; my $us = $date =~ s{(\d+)-(\d+)-(\d+)}{$2/$3/$1}r; # /r: return a copy say $us; # 06/21/2026 say $date; # 2026-06-21 (unchanged) ``` Η παγίδα: το γυμνό `s///` επεξεργάζεται τον στόχο του και επιστρέφει το *πλήθος* των αντικαταστάσεων, όχι τη νέα συμβολοσειρά - οπότε τα παραδείγματα αντιγράφουν πρώτα με `(my $t = $s) =~ ...` ή χρησιμοποιούν τη σημαία `/r`. Γράφοντας `my $new = ($s =~ s/a/b/)` βάζετε έναν αριθμό στο `$new`. Αυτή είναι η πιο συχνή έκπληξη της πρώτης μέρας. Σημειώστε επίσης ότι οι οριοθέτες είναι ελεύθεροι: τα `s{...}{...}` και `s#...#...#` σας γλιτώνουν από τις ανάποδες καθέτους στις καθέτους ενός μοτίβου διαδρομής, όπως το `${path##*/}` του κελύφους ήδη τις αποφεύγει. ## Διευθύνσεις και εύρη Η επιλογή γραμμών βάσει αριθμού ή μοτίβου - `grep`, `grep -n`, `awk 'NR==2'`, `sed -n '/a/,/b/p'` - γίνεται ένα μεταθεματικό `if` σε μια συνθήκη μέσα στον βρόχο. Ο αριθμός γραμμής είναι `$.`· ο έλεγχος μοτίβου είναι `/pat/` έναντι του `$_`. ```bash grep -n an data.txt # number + matching lines awk 'NR==2' data.txt # the second line ``` ```perl use v5.42; open my $fh, '<', '/tmp/data.txt' or die "open: $!"; while (<$fh>) { chomp; say "$. : $_" if /an/; # grep -n 'an' } close $fh; # 2 : banana ``` Ένα εύρος γραμμών - ο επιλογέας `/start/,/end/` του `sed`/`awk` - γίνεται ο χειριστής εύρους **flip-flop** της Perl `/start/ .. /end/`, αληθής από τη γραμμή που ταιριάζει με το αριστερό μοτίβο έως τη γραμμή που ταιριάζει με το δεξί, συμπεριλαμβανομένων: ```perl use v5.42; open my $fh, '<', '/tmp/data.txt' or die "open: $!"; while (<$fh>) { print if /banana/ .. /cherry/; # the /start/,/end/ range } close $fh; # banana # cherry ``` Η παγίδα: σε έναν λογικό έλεγχο το `..` είναι ο χειριστής flip-flop (εύρους), **όχι** ο χειριστής εύρους λίστας (που είναι το `1 .. 10` που χτίζει μια λίστα). Η Perl τα ξεχωρίζει βάσει περιβάλλοντος - στη λογική θέση ενός `if`, το `..` είναι ο επιλογέας εύρους γραμμών με κατάσταση· σε περιβάλλον λίστας χτίζει μια ακολουθία. Οι ίδιες δύο τελείες, που αποφασίζονται από το πού τις γράφετε. ## I/O, σωληνώσεις και επιτόπια επεξεργασία Αυτή είναι η καρδιά του οδηγού, επειδή είναι η καρδιά του προγραμματισμού κελύφους. Ό,τι κάνετε με `|`, `>`, `>>`, `2>&1`, `<; close $ph; chomp @nums; say "got: @nums"; # got: 1 2 3 ``` ```perl use v5.42; open my $sort, '|-', 'sort' or die "pipe: $!"; # write to command stdin print {$sort} "$_\n" for qw(banana apple cherry); close $sort; # apple # banana # cherry ``` **Ανακατεύθυνση.** Τα `>` και `>>` είναι οι λειτουργίες `open` `'>'` (περικοπή) και `'>>'` (προσθήκη)· ένα `open` τριών ορισμάτων με έναν λεξιλογικό περιγραφέα είναι το ιδίωμα. Το `print {$fh} ...` γράφει σε έναν περιγραφέα. Για να συγχωνεύσετε το stderr ενός παιδιού στο συλληφθέν ρεύμα (`2>&1`), κρατήστε την ανακατεύθυνση στην εντολή που δίνετε στα backticks: ```perl use v5.42; open my $fh, '>', '/tmp/sh_out.txt' or die "write: $!"; print {$fh} "line $_\n" for 1 .. 3; close $fh; my $both = `sh -c 'echo to-out; echo to-err 1>&2' 2>&1`; # merge stderr print $both; # to-out # to-err ``` **Here-docs.** Τα `<; # slurp all lines 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 "...: $!"` είναι υποχρεωτικό - το `$!` είναι η συμβολοσειρά σφάλματος του συστήματος, η σιωπηλή αποτυχία `2>/dev/null` του κελύφους γινόμενη ηχηρή και ρητή. Και όταν χτίζετε μια εντολή από μεταβλητές, προτιμήστε τη **μορφή λίστας** των `system`/`open` (`'ls', '-l', $dir`) έναντι μιας μοναδικής συμβολοσειράς με παρεμβολή: η μορφή λίστας παρακάμπτει εντελώς το κέλυφος, οπότε δεν υπάρχει διαχωρισμός λέξεων, ούτε ανάπτυξη glob, ούτε παράθεση σε εισαγωγικά να την κάνετε λάθος - η θεραπεία για την κόλαση παράθεσης του κελύφους. ## One-liners και διακόπτες Το one-liner είναι το οικείο έδαφος του προγραμματιστή κελύφους, και της Perl επίσης: το φίλτρο που ρίχνετε σε μια σωλήνωση. Η οικογένεια διακοπτών που το κάνει να λειτουργεί: το `-e` παρέχει το πρόγραμμα, το `-n` το τυλίγει σε έναν βρόχο χωρίς αυτόματη εκτύπωση, το `-p` το τυλίγει σε έναν βρόχο με αυτόματη εκτύπωση, το `-i` επεξεργάζεται αρχεία επιτόπια, το `-l` χειρίζεται τα τέλη γραμμών, και τα `-a`/`-F` αυτοδιαχωρίζουν κάθε γραμμή σε `@F` (το άμεσο αντίστοιχο του `awk`, πεδία στο `@F` αντί για `$1`..`$NF`). Τα `BEGIN { }` και `END { }` τρέχουν πριν και μετά τον βρόχο, όπως τα `BEGIN`/`END` του `awk`. ```bash grep error log.txt # filter lines awk -F: '{print $1}' /etc/passwd # first field awk '{s += $NF} END {print s}' data.txt # sum last field ``` ```perl perl -ne 'print if /error/' log.txt # filter lines perl -F: -ane 'print "$F[0]\n"' /etc/passwd # first field, -F sets split perl -lane '$s += $F[-1]; END { say $s }' data.txt # sum last field ``` Αυτά εμφανίζονται χωρίς έξοδο επειδή οι διακόπτες έμμεσου βρόχου δεν αναγνωρίζονται ακόμη από αυτό το build του `pperl` (δείτε τη σημείωση στην αρχή). Καθένας αντιστοιχίζεται σε μια επαληθευμένη μορφή ρητού βρόχου: το `perl -ne 'CODE'` είναι `while (<$fh>) { CODE }`, και το `perl -pe 'CODE'` είναι το ίδιο με μια τελική `print`. Η εκτελέσιμη μορφή «πρώτο πεδίο κάθε γραμμής»: ```perl use v5.42; open my $fh, '<', '/tmp/passwd.txt' or die "open: $!"; while (<$fh>) { # the implicit loop of -ane chomp; my @F = split /:/; # what -F: gives you in @F say $F[0]; # print the first field } close $fh; # root # daemon # bin ``` Η παγίδα: μέχρι να προστεθούν οι διακόπτες στο `pperl`, γράψτε τον ρητό βρόχο (τρέχει σήμερα και είναι ούτως ή άλλως αυτό στο οποίο αναπτύσσονται οι διακόπτες), και συμβουλευτείτε τον [οδηγό One-Liners](../oneliner/index.md) για τον πλήρη κατάλογο διακοπτών και δεκάδες συνταγές - είναι το πιο αποδοτικό πράγμα που μπορείτε να διαβάσετε ερχόμενοι από υπόβαθρο κελύφους, όπου το one-liner είναι το καθημερινό αντανακλαστικό. ## Ροή ελέγχου Τα `for`, `while`, `case` και `if`/`test` του κελύφους αντιστοιχίζονται σε βρόχους και συνθήκες της Perl, και αρκετές από τις αντιστοιχίσεις είναι ευχάριστα άμεσες. **Βρόχοι.** Το `for f in *; do` γίνεται `for my $f (glob "*")`· το glob αρχείων `*.txt` είναι `glob "*.txt"` ή η μορφή readline `<*.txt>`. ```bash for f in /tmp/sh_*.txt; do echo "file: $f" done ``` ```perl use v5.42; for my $f (sort glob "/tmp/sh_*.txt") { say "file: $f"; } # file: /tmp/sh_data.txt # file: /tmp/sh_passwd.txt ``` **Συνθήκες και `test`.** Αυτή είναι μια ευτυχής αντιστοίχιση: οι έλεγχοι αρχείων `[ -e ]`, `[ -d ]`, `[ -f ]` του κελύφους είναι οι **ίδιοι χειριστές `-X`** στην Perl. Η σύγκριση συμβολοσειρών και αριθμών χωρίζεται σε δύο οικογένειες, όπως γίνεται ανάμεσα στα `[ "$a" = "$b" ]` και `[ "$a" -eq "$b" ]`: η Perl χρησιμοποιεί `eq`/`ne` για συμβολοσειρές και `==`/`!=` για αριθμούς. Τα `-z`/`-n` (κενή / μη κενή συμβολοσειρά) του κελύφους γίνονται `!length` / `length`. ```bash if [ -f "$f" ] && [ -n "$name" ]; then echo ok fi [ "$a" = "$b" ] # string equality [ "$x" -eq "$y" ] # numeric equality ``` ```perl use v5.42; my $f = '/tmp/sh_data.txt'; my $name = 'set'; say "ok" if -f $f && length $name; # same -f, same idea # ok say "abc" eq "abc" ? "eq" : "ne"; # string compare say 10 == 10.0 ? "num-eq" : "num-ne"; # numeric compare # eq # num-eq ``` **`case`.** Το `case` του κελύφους δεν έχει δίδυμο μίας δεσμευμένης λέξης· η ιδιωματική Perl είναι μια αλυσίδα `for`/`if` ή ένας τριαδικός καταρράκτης (ή, για πολλούς κλάδους, ένας κατακερματισμός αποστολής που αντιστοιχίζει κλειδιά σε αναφορές κώδικα). ```bash case "$cmd" in start) echo starting ;; stop) echo stopping ;; *) echo "unknown: $cmd" ;; esac ``` ```perl use v5.42; for my $cmd (qw(start stop bogus)) { my $r = $cmd eq 'start' ? "starting" : $cmd eq 'stop' ? "stopping" : "unknown: $cmd"; say "$cmd -> $r"; } # start -> starting # stop -> stopping # bogus -> unknown: bogus ``` **Κατάσταση εξόδου.** Μετά από μια `system()`, η κατάσταση του παιδιού βρίσκεται στο `$?`, ακριβώς η μεταβλητή του κελύφους. Όμως το `$?` κρατά την ακατέργαστη κατάσταση `wait`, όχι τον σκέτο κωδικό εξόδου: ολισθήστε δεξιά κατά 8 για να πάρετε τον κωδικό που το κέλυφος θα εμφάνιζε ως `$?`. Οι δεσμευμένες λέξεις βρόχου `last` και `next` είναι το `break` και το `continue` του κελύφους. ```perl use v5.42; system('sh', '-c', 'exit 3'); say "raw \$? = $?"; # raw $? = 768 say "exit code = ", $? >> 8; # exit code = 3 ``` Η παγίδα: το `$? >> 8` είναι ο κωδικός εξόδου· τα χαμηλά 8 bits κρατούν το σήμα που σκότωσε το παιδί (αν υπάρχει). Το κέλυφος το κρύβει πίσω από το δικό του `$?`· στην Perl κάνετε εσείς την ολίσθηση. Το να το ξεχάσετε είναι ο λόγος που το `if ($? == 1)` μετά από μια εντολή που τερμάτισε με 1 είναι σχεδόν πάντα λάθος - η ακατέργαστη τιμή είναι `256`, όχι `1`. ## Μεταβλητές και δεδομένα Μια μεταβλητή κελύφους είναι πάντα μια συμβολοσειρά - `var=value`, χρησιμοποιούμενη ως `$var` ή `${var}`, και τοποθετημένη σε εισαγωγικά ως `"$var"` για να επιβιώσει του διαχωρισμού λέξεων. Το βαθμωτό της Perl είναι `my $var`, με λεξιλογική εμβέλεια, και **δεν χρειάζεται κανένας χορός παράθεσης σε εισαγωγικά**: ένα βαθμωτό της Perl κρατά μία τιμή και δεν ξαναδιαχωρίζεται κατά τη χρήση. Εκεί που το κέλυφος αναγκάζει τα πάντα να περάσουν μέσα από συμβολοσειρές, η Perl προσθέτει τους δύο περιέκτες που το κέλυφος ποτέ δεν είχε: διατεταγμένους `@arrays` και κλειδιού/τιμής `%hashes`. ```bash name="Ada" greeting="Hello, ${name}" langs="Perl Python" # a "list" is really a string + IFS ``` ```perl use v5.42; my $name = "Ada"; my $greeting = "Hello, $name"; # interpolation, like "${name}" my @langs = ("Perl", "Python"); # a real list, not a split string say $greeting; # Hello, Ada say "first: $langs[0]"; # first: Perl say "count: ", scalar @langs; # count: 2 ``` **Ορίσματα σεναρίου.** Οι θεσιακές παράμετροι του κελύφους αντιστοιχίζονται στο `@ARGV`. Το ναρκοπέδιο παράθεσης σε εισαγωγικά του `"$@"` έναντι του `$*` απλώς δεν υπάρχει: το `@ARGV` είναι ένας πραγματικός πίνακας, κάθε όρισμα ένα καθαρό στοιχείο ανεξάρτητα από τα κενά ή τα glob που περιείχε. Τα `$1`..`$9` γίνονται `$ARGV[0]`..`$ARGV[8]`, το `$#` (το πλήθος) γίνεται `scalar @ARGV`, και το `$0` (το όνομα του σεναρίου) γίνεται `$0`. ```bash echo "count: $#" echo "first: $1" echo "all: $@" ``` ```perl use v5.42; say "count: ", scalar @ARGV; # like $# say "first: $ARGV[0]"; # like $1 say "all: @ARGV"; # like "$@" # invoked as: pperl script.pl one two three # count: 3 # first: one # all: one two three ``` **Συσχετιστικοί πίνακες.** Ένας κατακερματισμός της Perl είναι το `declare -A` του κελύφους καμωμένο σωστά - δηλωμένος με `%`, προσπελάσιμος μία τιμή τη φορά με `$h{key}`, και πολύ πιο εργονομικός από τους πρόχειρα προσαρτημένους συσχετιστικούς πίνακες του κελύφους. ```perl use v5.42; my %count; $count{$_}++ for qw(apple pear apple fig apple pear); for my $k (sort keys %count) { say "$k: $count{$k}"; } # apple: 3 # fig: 1 # pear: 2 ``` Η παγίδα: μια μεταβλητή κελύφους είναι εξ ορισμού καθολική και μια μεταβλητή `my` της Perl έχει λεξιλογική εμβέλεια στο μπλοκ της - η αντίθετη προεπιλογή. Το `local` του κελύφους (δυναμική εμβέλεια μέσα σε μια συνάρτηση) είναι το πλησιέστερο στο `local` της Perl, αλλά για συνηθισμένες μεταβλητές θέλετε το `my`, που είναι αληθινή λεξιλογική εμβέλεια. Και η παρεμβολή συμβαίνει μόνο σε διπλά εισαγωγικά: το `"$name"` παρεμβάλλει, το `'$name'` είναι οι κυριολεκτικοί τέσσερις χαρακτήρες, ακριβώς όπως στο κέλυφος. > Η Perl έχει επίσης πλήρεις υπορουτίνες, αναφορές, αρθρώματα και OO αν το σενάριό σας ξεπεράσει ένα one-liner - δείτε τον [οδηγό Αντικειμενοστραφούς Προγραμματισμού](../oop/index.md) και τους άλλους οδηγούς coming-from. ## Παγίδες ερχόμενοι από το κέλυφος Οι παγίδες, συγκεντρωμένες για μια τελική ματιά πριν γράψετε: - **Το `<$fh>` κρατά την τελική νέα γραμμή.** Το `read` του κελύφους περικόπτει· η Perl όχι. Το `chomp` είναι το αντανακλαστικό σας σε κάθε ανάγνωση γραμμής. - **Το `split` είναι ξεχωριστό βήμα, και είναι μηδενοβάσει.** Τα πεδία είναι `$f[0]`, `$f[1]`, όχι το βάσει-του-ένα `$1` του `awk`. Το `split ' '` (μαγικά κενά) περικόπτει και συμπτύσσει· το `split / /` (ένα κυριολεκτικό κενό) όχι. - **Το `s///` επιστρέφει ένα πλήθος, όχι τη νέα συμβολοσειρά.** Το `my $x = $s =~ s/a/b/` βάζει το *πλήθος* αντικαταστάσεων στο `$x`. Αντιγράψτε πρώτα (`(my $t = $s) =~ s/.../.../`) ή χρησιμοποιήστε τη σημαία `/r`. - **Το `$? >> 8` είναι ο κωδικός εξόδου.** Το ακατέργαστο `$?` μετά τη `system` είναι η πλήρης κατάσταση wait· ο κωδικός εξόδου είναι τα υψηλά 8 bits. Το `if ($? == 1)` είναι σχεδόν πάντα σφάλμα· θέλετε `if (($? >> 8) == 1)`. - **Η `open` δεν εγείρει σφάλμα σε αποτυχία.** Χρησιμοποιήστε `open my $fh, '<', $path or die "...: $!"`. Το `$!` είναι η συμβολοσειρά σφάλματος του συστήματος - η σιωπηλή αποτυχία του κελύφους γινόμενη ρητή. - **Προτιμήστε τη μορφή λίστας των `system`/`open` έναντι μιας συμβολοσειράς με παρεμβολή.** Το `system('ls', '-l', $dir)` δεν τρέχει κανένα κέλυφος: δεν υπάρχει διαχωρισμός λέξεων, ούτε έκπληξη glob, ούτε κόλαση παράθεσης. Η μορφή συμβολοσειράς (`system "ls -l $dir"`) επανεισάγει κάθε παγίδα παράθεσης κελύφους από την οποία ήρθατε εδώ να ξεφύγετε. - **Το `my` είναι λεξιλογικό· οι μεταβλητές κελύφους είναι καθολικές.** Δηλώστε με `my` και περιορίστε την εμβέλεια στο μπλοκ· καταφύγετε στο `local` μόνο για τη συμπεριφορά δυναμικής εμβέλειας του κελύφους, που σπάνια είναι αυτό που θέλετε. - **Η σύγκριση συμβολοσειρών έναντι αριθμών είναι δύο οικογένειες.** `eq`/`ne` για συμβολοσειρές, `==`/`!=` για αριθμούς - ο διαχωρισμός `[ = ]` έναντι `[ -eq ]`, αλλά οι χειριστές είναι αντεστραμμένοι σε σχέση με το κέλυφος, οπότε διαβάστε τους προσεκτικά. - **Οι διακόπτες έμμεσου βρόχου (`-n`/`-p`/`-a`/`-F`/`-i`/`-l`) δεν αναγνωρίζονται ακόμη από αυτό το build του `pperl`.** Μόνο το `-e` λειτουργεί σήμερα. Γράψτε τον ρητό βρόχο `while (<$fh>) { ... }`, που είναι ακριβώς αυτό στο οποίο αναπτύσσονται οι διακόπτες, μέχρι να προστεθούν.