Μαθήματα Perl (Μέρος 3): Ελεγχος ροής, αρχεία και αναφορές

dimitris | Τρί, 08/27/2013 - 07:34 | 15'

Αν είναι καλογραμμένα τα script της Perl μπορούν να κάνουν έξυπνα πράγματα: να παίρνουν δεδομένα από το σκληρό, να γράφουν αναφορές του τι έκαναν σε ένα log αρχείο και να εκτελούν κώδικα μόνο όταν υπάρχουν οι ζητούμενες συνθήκες. Αυτά θα δούμε σε αυτό το άρθρο.

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

Τελεστές ελέγχου ροής

Η Perl διαθέτει τους περισσότερους από τους τελεστές ελέγχου της C, και μερικούς μόνο με άλλα ονόματα και σύνταξη. Οι δηλώσεις If-else, για παράδειγμα είναι ακριβώς ίδιες ενώ η else if γράφεται elsif:

if (MONEY > 50) {
 print “Ask George for a little extra money\n”;
}
elsif ((MONEY > 0) && ($MONEY <=50)) {
 print “Ask George for MORE money\n”;
} else {
 print “George! I’m in trouble!\n”;
}

Εναλλακτικά, υπάρχει η unless, που σημαίνει ακριβώς το αντίθετο του if:

unless ($MONEY < 1000000) {
 print “Better ask George for some money...\n”;
}

Η δήλωση while μπορεί να πάρει δύο μορφές:

while ($MONEY > 1000000) {
print “Ask for more money ...\n”;
}
# ή με το ίδιο αποτέλεσμα:
do {
 print “Ask for more money...\n”;
} while ($MONEY < 1000000);

Δεν θα τυπωθεί τίποτε αν έχετε περισσότερα από 1000000 όταν ξεκινήσει το script. Εάν θέλετε να είστε σίγουροι ότι οτιδήποτε περιέχεται στις αγκύλες θα συμβεί τουλάχιστον μια φορά στο πρόγραμμα, χρησιμοποιήστε το βρόχο until:

do {
 print “Ask for at least 10 euros more...\n”;
} until ($MONEY > 1000000);

Οι βρόχοι ορίζονται και με τα κλασσικά for και foreach. Η βασική τους διαφορά είναι ότι η foreach προτιμάται για επαναλήψεις σε hashes ή arrays

for ($i = 0 ; $i <100 ; $i++) {
 #κάνε κάτι 100 φορές
}
foreach $PERSON (keys %DIR){
  print “The phone number of $PERSON IS $DIR{$PERSON}{‘Phone number’}\n”;

Στην δεύτερη περίπτωση, η $PERSON φορτώνεται σε κάθε επανάληψη με την τιμή ενός διαφορετικού κλειδιού μέσα στο hash. Εάν παραλειφθεί, οι τιμές κάθε κλειδιού πηγαίνουν στην πανταχού παρούσα μεταβλητή $_.

Παίξτε με αρχεία!

Πριν αρχίσετε να δουλεύετε με αρχεία από το script σας, καλό είναι να ελέγξετε ότι έχει τις κατάλληλες ιδιότητες (π.χ. υπάρχει, είναι αναγνώσιμο κτλ). Η Perl παρέχει διάφορους τελεστές “ελέγχου αρχείων” για να το κάνετε αυτό. Τα επόμενα είναι απλώς μια μικρή περίληψη, αλλά για μια πλήρη λίστα των τελεστών αυτών μπορείτε να πάτε στο www.unix.org.ua/orelly/perl/prog3/ch03_10.htm

if (-e $FILE) #έλεγχος ύπαρξης

if (-r $FILE) #έλεγχος ύπαρξης και δυνατότητας ανάγνωσης

if (-d $FILE) #έλεγχος ύπαρξης και εάν είναι υποφάκελος

Αφού κάνετε τον έλεγχο, η ανάγνωση και η εγγραφή σε αρχεία με την Perl είναι απλή υπόθεση με τις ομώνυμες συναρτήσεις για να ανοίγετε και να κλείνετε κάθε αρχείο:

open ( FILE_HANDLE, name_of_file) || die “Oh, what happened to my file!\n”;
# κάντε οτιδήποτε θέλετε με το αρχείο...
close (FILE_HANDLE)

Η συνάρτηση die τερματίζει το script και τυπώνει το σχετικό string, που της δώσατε σαν όρισμα, στην τυπική έξοδο (οθόνη). Στην πρώτη εντολή πάνω, ο τελεστής OR (||) σταματάει το script μόνο εάν το αρχείο δεν μπορεί να ανοιχθεί. Δεν είναι απαραίτητο να χρησιμοποιήσετε την die αλλά αν την ξεχάσετε σε κάποιο άλλο πρόγραμμα μπορεί να ξοδέψετε πολλές ώρες χωρίς να δουλεύει τίποτε.

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

open (MY_FILE, “< $FILENAME”) or die (“Could not read from $FILENAME\n”);

Για εκ νέου εγγραφή (με το >):

open(MY_FILE, “> /home/mylogin/filename”) or die (“Could not write to your file\n”);

Για πρόσθεση στο τέλος υπάρχοντος αρχείου (με το >>):

open (MY_FILE, “>> $SUBFOLDER/$FILENAME”) or die (“Could not append MORE date to $SUBFOLDER/$FILENAME\n”);

Να είστε προσεκτικοί όταν ανοίγετε αρχείο με >, γιατί θα σβηστούν οτιδήποτε δεδομένα έχει ήδη. Όταν θέλετε να διατηρήσει τα δεδομένα του, τότε καλύτερα χρησιμοποιήστε προσθήκη (με >>), όπως η τελευταία εντολή πάνω. Εάν δεν σημειώσετε τον τρόπο ανοίγματος, τότε η Perl για ασφάλεια θα ανοίξει το αρχείο σας μόνο για ανάγνωση.

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

Ωραία, ανοίξατε ένα αρχείο. Πως διαβάζετε ή γράφετε σε αυτό; Για να γράψετε σε ένα αρχείο υπάρχει η δήλωση print, που γνωρίζετε ήδη, και η παραπλήσια printf εάν θέλετε να μορφοποιήσετε την έξοδο καλύτερα. Για να δείτε τη διαφορά ανάμεσα σε αυτές τις δύο, σώστε το παρακάτω script σε ένα αρχείο:

#! /usr/bin/perl
open (TEST, “< testfile.txt”) || die “Cannot open testfile.txt\n”;
while (<TEST>) {
 #Η τρέχουσα γραμμή φορτώνεται στην μεταβλητή $_
 $LINE= $_;
 #Κάνε κάτι με τη $LINE
}
close(TEST);
#...ή σώσε το περιεχόμενό τους στo @ALL_THE_LINES
open(TEST, “< testfile.txt”) || die “Cannot open testfile.txt\n”;
@ALL_THE_LINES=<TEST>;
close (TEST);

 

Μορφοποίηση εξόδου και αναφορών

Η συνάρτηση printf εκτυπώνει ένα μείγμα μεταβλητών και συμβολοσειρών μορφοποιημένων με τον τρόπο που εσείς θέλετε, αλλά δεν είναι ιδιαίτερα πρακτική όταν έχετε να φορμάρετε μια έξοδο πολλών γραμμών. Ευτυχώς, η Perl (μια και είναι report language) έχει λύσεις για αυτές τις καταστάσεις.

Φανταστείτε ένα γενικό script για τηλεφωνικό κατάλογο, το πρώτο μέρος του οποίου αντλεί τα στοιχεία $NAME, $STREET_NAME_AND_NUMBER, $CITY και $POST_CODE κάθε εγγραφής από μια βάση δεδομένων. Το δεύτερο μέρος πρέπει να τυπώνει αυτές τις μεταβλητές στην κονσόλα με τον πιο συμπαγή και ευανάγνωστο τρόπο. Μια λύση είναι να κάνετε το εξής: Βάλτε όλες τις εντολές σε ένα βασικό template (πρότυπο) και μαρκάρετε την αρχή και το τέλος με κάποια σταθερή συμβολοσειρά ως εξής:

print << END_OF_RECORD;
Name : $NAME
Street: $STREET
$CITY $POST_CODE $COUNTRY
END OF RECORD

Οι παραπάνω γραμμές κάνουν κάτι πολύ απλό. Όταν το script φτάσει στην εντολή print, τυπώνει όλο το κείμενο μέχρι το END_OF_RECORD, αντικαθιστώντας επιπλέον τις τιμές των μεταβλητών σε κάθε γραμμή. Το μόνο πρόβλημα είναι ότι δεν μπορεί να κάνει justification στο κείμενο, και έτσι κάθε εγγραφή θα έχει τις $STREET και $COUNTRY τοποθετημένες σε διαφορετικά σημεία και το αποτέλεσμα θα είναι αντιαισθητικό.

Μπορείτε να λύσετε αυτό το πρόβλημα με δύο εντολές, την format και την write. Η πρώτη χρησιμοποιείται για να καθορίσει που τοποθετείται κάθε μεταβλητή και πόσους χαρακτήρες οθόνης μπορεί να γεμίσει. Αυτό γίνεται με “οπτικοποίηση” κάθε γραμμής εξόδου, όπου κάθε όρισμα @ δηλώνει την θέση όπου θα τυπωθεί η αντίστοιχη μεταβλητή και τα < ορίζουν το πλάτος (σε αριθμό χαρακτήρων) που θα καταλαμβάνει:

format STDOUT_RECORD =
Name: @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$NAME
Street: @>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
$STREET
@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<@>>>>>>>@>>>>>>>>>>>>>
$CITY,$POST_CODE,$COUNTRY

Τα παραπάνω ιερογλυφικά, καθορίζουν ένα πρότυπο, STDOUT_RECORD, το οποίο αποτελείται από τρεις “οπτικές γραμμές”, που συμβολίζουν την μορφή κάθε γραμμής εξόδου. Η διαφορά τώρα είναι ότι κάθε μεταβλητή έχει συγκεκριμένο πεδίο (θέση και πλάτος) για να τυπωθεί. Για παράδειγμα, η πρώτη γραμμή έχει ένα @ και 37 χαρακτήρες <. Αυτό απλά σημαίνει ότι η μεταβλητή που ακολουθεί ($ΝΑΜΕ) θα τυπωθεί από τη θέση @, θα είναι 37 χαρακτήρες το πολύ και θα στοιχίζεται αριστερά. Με την ίδια σύνταξη, η $POST_CODE θα τυπώνεται στο ίδιο σημείο της τρίτης γραμμής, θα είναι το πολύ 7 χαρακτήρες και στοιχισμένη δεξιά.

Όμως αυτά είναι απλά ο ορισμός του προτύπου. Όταν θελήσετε να γράψετε τα πραγματικά δεδομένα θα το κάνετε με τον εξής τρόπο:

$~ = “STDOUT_RECORD”;
write;

Με άλλα λόγια, αυτό σημαίνει: “γράψε στο STDOUT χρησιμοποιώντας το πρότυπο που λέγεται STDOUT_RECORD”. Η εντολή format της Perl έχει πολλά ακόμη διαθέσιμα πεδία: με το σύμβολο # προσδιορίζετε ευθυγραμμισμένα αριθμητικά πεδία ενώ με το ^ ορίζετε μπλοκ κειμένου σε πολλές γραμμές μέσα στο ίδιο πρότυπο. Για να έχετε κεντραρισμένο κείμενο χρησιμοποιήστε το σύμβολο | αντί των < και >.

Μαθαίνοντας Perl

Η σύνταξη της Perl μπορεί να είναι αρκετά μπερδεμένη, αλλά πολλές φορές μοιάζει με ανθρώπινη γλώσσα. Εξ’ ορισμού, οι δηλώσεις if-then γράφονται σε μια μορφή που μοιάζει πολύ με της C, με αγκύλες να ενθυλακώνουν τις εντολές της διακλάδωσης. Όμως, μπορείτε να γράψετε απλές εντολές διακλάδωσης σχεδόν σε απλά αγγλικά, π.χ.:

print “SORRY, no more money” if ($ACCOUT_BALANCE <=0);

print “Access Denied!\n” unless ($WHO_IS_AT_THE_DOOR eq ‘Me’);

 

Συνδυάζοντας Perl με άλλα προγράμματα

Μια από τις ποιότητες του Unix είναι η δυνατότητα του να συνδυάζει μικρά εργαλεία σε μια αλληλουχία και να δημιουργείται έτσι ένα πανίσχυρο πρόγραμμα. Μπορείτε να κάνετε το ίδιο με την Perl. Το τρικ είναι να χρησιμοποιήσετε το σύμβολο | (πίπα) πριν ή μετά το εξωτερικό πρόγραμμα που θέλετε να εκτελέσετε, αντί για έναν όνομα αρχείου με > ή <. Για παράδειγμα:

#Χρησιμοποίησε την έξοδο του program1
open(README, “program1 |”) or die “Could not open program1\n”;
#Στείλτε δεδομένα στο program2
open(README, “| program2 |”) or die “Could not open program2\n”;

 

Δείτε ακόμα:

Δώσε αστέρια!

MO: 5 (ψήφοι: 2)