[successivo] [precedente] [inizio] [fine] [indice generale] [indice analitico]


Capitolo 4.   Perl: introduzione

Perl è un linguaggio di programmazione interpretato (o quasi) che quindi viene eseguito da un interprete senza bisogno di generare un eseguibile binario. In questo senso, i programmi Perl sono degli script eseguiti dal programma perl che per convenzione dovrebbe essere collocato in /usr/bin/.

Perl è molto importante in tutti gli ambienti Unix e per questo è molto utile conoscerne almeno i rudimenti. Volendo fare una scala di importanza, subito dopo la programmazione con le shell Bourne e derivate, viene la programmazione in Perl.

I capitoli, che a partire da questo, sono dedicati a Perl, introducono solamente il linguaggio, che per essere studiato seriamente richiederebbe invece molto tempo e la lettura di molta documentazione.

4.1   Struttura fondamentale

Dal momento che i programmi Perl vengono realizzati in forma di script, per convenzione occorre indicare il nome del programma interprete nella prima riga.

#!/usr/bin/perl

Per l'esecuzione di script da parte di un interprete non si può fare affidamento sul percorso di ricerca degli eseguibili (la variabile di ambiente PATH), è quindi importante che il binario perl si trovi dove previsto. Questa posizione (/usr/bin/perl) è quella standard ed è opportuno che sia rispettata tale consuetudine, altrimenti i programmi in Perl di altri autori non potrebbero funzionare nel proprio sistema senza una variazione di tutti i sorgenti.

Il buon amministratore di sistema farebbe bene a collocare dei collegamenti simbolici in tutte le posizioni in cui sarebbe possibile che venisse cercato l'eseguibile perl: /bin/perl, /usr/bin/perl e /usr/local/bin/perl.

Come si può intuire, il simbolo # rappresenta l'inizio di un commento.

#!/usr/bin/perl
#
# Esempio di intestazione e di commenti in Perl.
...

Un'altra convenzione che riguarda gli script Perl è l'estensione: .pl, anche se l'utilizzo o meno di questa non costituisce un problema.

4.1.1   Istruzioni

Le istruzioni seguono la convenzione del linguaggio C, per cui terminano con un punto e virgola (;) e i raggruppamenti di queste, detti anche blocchi, si fanno utilizzando le parentesi graffe ({ }).

istruzione ;
{ istruzione ;  istruzione ;  istruzione ;}

Generalmente, un'istruzione può essere interrotta e ripresa nella riga successiva, dal momento che la sua conclusione è dichiarata chiaramente dal punto e virgola finale.

4.1.2   Nomi

I nomi utilizzati per identificare ciò che si utilizza all'interno del programma seguono regole determinate. In particolare:

Spesso i nomi sono preceduti da un simbolo che ne definisce il contesto:

4.1.3   Contesto operativo

Perl è un linguaggio di programmazione con cui gli elementi che si indicano hanno un valore riferito al contesto in cui ci si trova. Questo significa, per esempio, che un array può essere visto come: una lista di elementi, il numero degli elementi contenuti, o una stringa contenente tutti i valori degli elementi contenuti.

In pratica, ciò serve a fare in modo che i dati siano trasformati nel modo più adatto al contesto, al quale è importante fare attenzione.

4.1.4   Tipi di dati

I tipi di dati più importanti che si possono gestire con Perl sono:

Le variabili di Perl vengono create semplicemente con l'assegnamento di un valore, senza la necessità di dichiarare il tipo o la dimensione. Le conversioni dei valori numerici sono fatte automaticamente in base al contesto.

In Perl non esiste un tipo di dati logico (nel senso di Vero o Falso); solo il risultato di una condizione lo è, ma non equivale a un valore gestibile in una variabile. Da un punto di vista logico-booleano, i valori seguenti vengono considerati equivalenti a Falso:

Qualunque altro valore viene trattato come equivalente a Vero.

4.1.5   Esecuzione dei programmi Perl

Per poter eseguire un programma Perl, così come accade per qualunque altro tipo di script, occorre attivare il permesso in esecuzione per il file che lo contiene.

chmod +x  programma_perl

Sembra banale o evidente, ma spesso ci si dimentica di farlo, e quello che si ottiene è il classico permesso negato: Permission denied.

4.2   Variabili e costanti scalari

La gestione delle variabili e delle costanti in Perl è molto simile a quella delle shell comuni. Una variabile scalare è quella che contiene un valore unico, contrapponendosi generalmente all'array che in Perl viene definito come variabile contenente una lista di valori.

4.2.1   Variabili

Le variabili scalari di Perl possono essere dichiarate in qualunque punto del programma e la loro dichiarazione coincide con l'inizializzazione, cioè l'assegnamento di un valore. I nomi delle variabili scalari iniziano sempre con il simbolo dollaro ($).

(1)

$ variabile_scalare  =  valore

L'assegnamento di un valore a una variabile scalare implica l'utilizzo di quanto si trova alla destra del simbolo di assegnamento (=) come valore scalare: una stringa, un numero o un riferimento. È il contesto a decidere il risultato dell'assegnamento.

4.2.2   Variabili predefinite

Perl fornisce automaticamente alcune variabili scalari che normalmente non devono essere modificate dai programmi. Tali variabili servono per comunicare al programma alcune informazioni legate al sistema, oppure l'esito dell'esecuzione di una funzione, esattamente come accade con i parametri delle shell comuni. La tabella 4.1 mostra un elenco di alcune di queste variabili standard. Si può osservare che i nomi di tali variabili non seguono la regola per cui il primo carattere deve essere un simbolo di sottolineatura o una lettera. Questa eccezione consente di evitare di utilizzare inavvertitamente nomi corrispondenti a variabili predefinite.

Nome Descrizione
$$ Numero PID del programma.
$< Numero UID reale dell'utente che esegue il programma.
$> Numero UID efficace dell'utente che esegue il programma.
$? Lo stato dell'ultima chiamata di sistema.
$_ Argomento predefinito di molte funzioni.
$0 Il nome del programma.
$" Separatore di lista.
$/ Separatore di righe per l'input (input record separator).

Tabella 4.1. Elenco di alcune variabili standard di Perl.

4.2.3   Costanti

Le costanti scalari più importanti sono di tipo stringa o numeriche. Le prime richiedono la delimitazione con apici doppi o singoli, mentre quelle numeriche non richiedono alcuna delimitazione.

Perl gestisce le stringhe racchiuse tra apici doppi in maniera simile a quanto fanno le shell tradizionali:

Anche le stringhe racchiuse tra apici singoli sono gestite in modo simile alle shell tradizionali:

Inoltre, davanti all'apice di inizio di una tale stringa, è necessario sia presente uno spazio.

La tabella 4.2 mostra un elenco di alcune di queste sequenze di escape utilizzabili nelle stringhe.

Escape Corrispondenza
\\ \
\" "
\$ $
\@ @
\' '
\t <HT>
\n <LF>
\r <CR>
\f <FF>
\b <BS>
\a <BELL>
\e <ESC>
\0 nNumero ottale rappresentato da  n .
\x hNumero esadecimale rappresentato da  h .

Tabella 4.2. Elenco di alcune sequenze di escape utilizzabili nelle stringhe delimitate con gli apici doppi.

Quando all'interno di stringhe tra apici doppi si indicano delle variabili (scalari e non), potrebbe porsi un problema di ambiguità causato dalla necessità di distinguere il nome delle variabili dal resto della stringa. Quando dopo il nome della variabile segue un carattere o un simbolo che non può fare parte del nome (come uno spazio o un simbolo di punteggiatura), Perl non ha difficoltà a individuare la fine del nome della variabile e la continuazione della stringa. Quando ciò non è sufficiente, si può delimitare il nome della variabile tra parentesi graffe, così come si fa con le shell tradizionali.

${ variabile }
@{ variabile }

4.2.3.1   Costanti numeriche

Le costanti numeriche possono essere indicate nel modo consueto, quando si usa la numerazione a base decimale, oppure anche in esadecimale e in ottale.

Con la numerazione a base 10, si possono indicare interi nel modo normale e valori decimali utilizzando il punto come separazione tra la parte intera e la parte decimale. Si può utilizzare anche la notazione esponenziale.

Un numero viene trattato come esadecimale quando è preceduto dal prefisso 0x e come ottale quando inizia con uno zero.

Quando un numero ottale o esadecimale è contenuto in una stringa, l'eventuale conversione in numero non avviene automaticamente, come invece accade in presenza di notazioni in base 10.

4.2.4   Esempi

L'esempio seguente è il più banale, emette semplicemente la stringa "Ciao Mondo!\n" attraverso lo standard output. È da osservare la parte finale, \n, che completa la stringa con un codice di interruzione di riga in modo da portare a capo il cursore in una nuova riga dello schermo.

#!/usr/bin/perl

print "Ciao Mondo!\n";

Se il file si chiama 1.pl, lo si deve rendere eseguibile e quindi si può provare il suo funzionamento.

chmod +x 1.pl[Invio]

1.pl[Invio]

Ciao Mondo!

---------

L'esempio seguente genera lo stesso risultato di quello precedente, ma con l'uso di variabili. Si può osservare che solo alla fine viene emesso il codice di interruzione di riga.

#!/usr/bin/perl

$primo = "Ciao";
$secondo = "Mondo";
print $primo;
print " ";
print $secondo;
print "!\n";

---------

L'esempio seguente genera lo stesso risultato di quello precedente, ma con l'uso dell'interpolazione delle variabili all'interno di stringhe racchiuse tra apici doppi.

#!/usr/bin/perl

$primo = "Ciao";
$secondo = "Mondo";
print "$primo $secondo!\n";

---------

L'esempio seguente emette la parola CiaoMondo senza spazi intermedi utilizzando la tecnica delle parentesi graffe.

#!/usr/bin/perl

$primo = "Ciao";
print "${primo}Mondo!\n";

---------

L'esempio seguente mostra il comportamento degli apici singoli per delimitare le stringhe. Non si ottiene più l'interpolazione delle variabili.

#!/usr/bin/perl

$primo = "Ciao";
$secondo = "Mondo";
print '$primo $secondo!\n';

Se il file si chiama 5.pl, si può verificare il suo funzionamento nel modo seguente:

chmod +x 5.pl[Invio]

5.pl[Invio]

$primo $secondo!\n

Inoltre, mancando il codice di interruzione di riga finale, l'invito della shell riappare subito alla destra di quanto visualizzato.

---------

L'esempio seguente mostra l'uso di una costante e di una variabile numerica. Il valore numerico viene convertito automaticamente in stringa al momento dell'interpolazione.

#!/usr/bin/perl

$volte = 1000;
$primo = "Ciao";
$secondo = "Mondo";
print "$volte volte $primo $secondo!\n";

Se il file si chiama 6.pl, si può verificare il suo funzionamento nel modo seguente:

chmod +x 6.pl[Invio]

6.pl[Invio]

1000 volte Ciao Mondo!

---------

L'esempio seguente permette di prendere confidenza con le variabili predefinite descritte in precedenza.

#!/usr/bin/perl

print "Nome del programma: $0\n";
print "PID del programma: $$\n";
print "UID dell'utente: $<\n";
print "Ultima chiamata di sistema: $?\n";

Se il file si chiama 7.pl, si può verificare il suo funzionamento nel modo seguente:

chmod +x 7.pl[Invio]

7.pl[Invio]

Il risultato potrebbe essere simile a quello seguente:

Nome del programma: ./7.pl
PID del programma: 717
UID dell'utente: 500
Ultima chiamata di sistema: 0

4.3   Array e liste

Perl gestisce gli array in modo dinamico, nel senso che possono essere allungati e accorciati a piacimento. Quando si parla di array si pensa generalmente a una variabile che abbia questa forma; ma Perl permette di gestire delle costanti array, definite liste.

Generalmente, il primo elemento di un array o di una lista ha indice zero. Questo assunto può essere cambiato agendo su una particolare variabile predefinita, ma ciò è sconsigliabile.

4.3.1   Liste

Le liste sono una sequenza di elementi scalari, di qualunque tipo, separati da virgole, racchiusi tra parentesi tonde. L'ultimo elemento può essere seguito o meno da una virgola, prima della parentesi chiusa.

( elemento , ...)

La lista vuota, o nulla, si rappresenta con le semplici parentesi aperta e chiusa:

()

Seguono alcuni esempi in cui si mostrano diversi modi di indicare la stessa lista.

("uno", "due", "tre", "quattro", "ciao")
("uno", "due", "tre", "quattro", "ciao",)
("uno",
 "due",
 "tre",
 "quattro",
 "ciao",)
(
    "uno",
    "due",
    "tre",
    "quattro",
    "ciao",
)

Una lista può essere utilizzata per inizializzare un array, ma se si pretende di assegnare una lista a un variabile scalare, si ottiene in pratica che la variabile scalare contenga solo il valore dell'ultimo elemento della lista (alla variabile vengono assegnati, in sequenza, tutti gli elementi della lista, per cui, quello che resta è l'ultimo). Per esempio:

$miavar = ("uno", "due", "tre", "quattro", "ciao");

assegna a $miavar solo la stringa "ciao".

Una lista di valori può essere utilizzata con un indice, per fare riferimento solo a uno di tali valori. Naturalmente ciò è utile quando l'indice è rappresentato da una variabile. L'esempio seguente mostra la trasformazione di un indice ($ind), che abbia un valore numerico compreso tra zero e nove, in un termine verbale.

$numverb = (
        "zero",
        "uno",
        "due",
        "tre",
        "quattro",
        "cinque",
        "sei",
        "sette",
        "otto",
        "nove",
)[$ind];

Gli elementi contenuti in una lista che non sono scalari, vengono interpolati, incorporando in quel punto tutti gli elementi che questi rappresentano. Gli eventuali elementi non scalari nulli, non rappresentano alcun elemento e vengono semplicemente ignorati. Per esempio, la lista

("uno", "due", (), ("tre", "quattro", "cinque"), "sei")

è perfettamente identica a quella seguente:

("uno", "due", "tre", "quattro", "cinque", "sei")

Naturalmente ciò ha maggiore significato quando non si tratta semplicemente di liste annidate, ma di array collocati all'interno di liste.

4.3.2   Array

L'array è una variabile contenente una lista di valori di qualunque tipo, purché scalari. Il nome di un array inizia con il simbolo @ quando si fa riferimento a tutto l'insieme dei suoi elementi o anche solo a parte di questi. Quando ci si riferisce a un solo elemento di questo si utilizza il dollaro.

(3)

Un array può essere dichiarato vuoto, con la sintassi seguente,

@ array  = ()

oppure assegnandogli una lista di elementi.

@ array  = ( elemento , ...)

Il riferimento a un solo elemento di un array viene indicato con la notazione seguente (le parentesi quadre fanno parte della notazione),

$ array [ indice ]

mentre il riferimento a un raggruppamento può essere indicato in vari modi.

@ array [ indice1 , indice2 ,...]

In tal caso ci si riferisce a un sottoinsieme composto dagli elementi indicati dagli indici contenuti all'interno delle parentesi quadre.

@ array [ indice_iniziale .. indice_finale ]

In questo modo ci si riferisce a un sottoinsieme composto dagli elementi contenuti nell'intervallo espresso dagli indici iniziale e finale.

Nella gestione degli array sono importanti due variabili predefinite:

Assegnare un array o parte di esso a una variabile scalare, significa in pratica assegnare un numero intero esprimente il numero di elementi in esso contenuti. Per esempio,

@mioarray = ("uno", "due");
$mioscalare = @mioarray;

significa assegnare a $mioscalare il valore due.

Inserire un array o parte di esso in una stringa delimitata con gli apici doppi, implica l'interpolazione degli elementi, separati con quanto contenuto nella variabile $" (il separatore di lista). La variabile predefinita $" contiene normalmente uno spazio singolo. Per esempio,

@mioarray = ("uno", "due");
$mioscalare = "@mioarray";

significa assegnare a $mioscalare la stringa "uno due".

Perl fornisce degli array predefiniti, di cui il più importante è @ARGV che contiene l'elenco degli argomenti ricevuti dalla riga di comando.

4.3.3   Esempi

L'esempio seguente permette di verificare quanto espresso sugli array di Perl.

#!/usr/bin/perl

# Dichiara l'array assegnandogli sia stringhe che numeri
@elenco = ("primo", "secondo", 3, 4, "quinto");

# Attraverso l'assegnamento seguente, $elementi riceve il numero di
# elementi contenuti nell'array.
$elementi = @elenco;

# Emette tutte le informazioni legate all'array.
print "L'array contiene $elementi elementi.\n";
print "L'indice iniziale è $[.\n";
print "L'ultimo elemento si raggiunge con l'indice $#elenco.\n";

# Emette in ordine tutti gli elementi dell'array.
print "L'array contiene: $elenco[0] $elenco[1] $elenco[2] $elenco[3] $elenco[4].\n";

# Idem
print "Anche in questo modo si legge il contenuto dell'array: @elenco.\n";

Se il file si chiama 11.pl, si può verificare il suo funzionamento nel modo seguente:

chmod +x 11.pl[Invio]

11.pl[Invio]

L'array contiene 5 elementi.
L'indice iniziale è 0.
L'ultimo elemento si raggiunge con l'indice 4.
L'array contiene: primo secondo 3 4 quinto.
Anche in questo modo si legge il contenuto dell'array: primo secondo 3 4 quinto.

---------

L'esempio seguente mostra il funzionamento dell'array predefinito @ARGV.

#!/usr/bin/perl

print "Il programma $0 è stato avviato con gli argomenti seguenti:\n";
print "@ARGV\n";
print "Il primo argomento era $ARGV[0]\n";
print "e l'ultimo era $ARGV[$#ARGV].\n";

Se il file si chiama 12.pl, si può verificare il suo funzionamento nel modo seguente:

chmod +x 12.pl[Invio]

12.pl carbonio idrogeno ossigeno[Invio]

Il programma ./12.pl è stato avviato con gli argomenti seguenti:
carbonio idrogeno ossigeno
Il primo argomento era carbonio
e l'ultimo era ossigeno.

4.4   Array associativi o hash

L'array associativo, o hash, è un tipo speciale di array che normalmente non si trova negli altri linguaggi di programmazione. Gli elementi sono inseriti a coppie, dove il primo elemento della coppia è la chiave di accesso per il secondo.

Il nome di un hash inizia con il segno di percentuale (%), mentre il riferimento a un elemento scalare di questo si fa utilizzando il dollaro, mentre l'indicazione di un sottoinsieme avviene con il simbolo @, come per gli array.

La dichiarazione, ovvero l'assegnamento di un array associativo, si esegue in uno dei due modi seguenti.

% array_associativo  = ( chiave ,  elemento , ...)
% array_associativo  = ( chiave  =>  elemento , ...)

La seconda notazione esprime meglio la dipendenza tra la chiave e l'elemento che con essa viene raggiunto. L'elemento che funge da chiave viene trattato sempre come stringa, mentre gli elementi abbinati alle chiavi possono essere di qualunque tipo scalare. In particolare, nel caso si utilizzi l'abbinamento tra chiave e valore attraverso il simbolo =>, ciò che sta alla sinistra di questo viene interpretato come stringa in ogni caso, permettendo di eliminare la normale delimitazione attraverso apici.

Un elemento singolo di un hash viene indicato con la notazione seguente, dove le parentesi graffe fanno parte dell'istruzione.

$ array_associativo { chiave }

La chiave può essere una costante stringa o un'espressione che restituisce una stringa. La costante stringa può anche essere indicata senza apici.

Un sottoinsieme di un hash è un'entità equivalente a un array e viene indicato con la notazione seguente:

@ array_associativo { chiave1 , chiave2 ,...}

Perl fornisce alcuni array associativi predefiniti. Il più importante è %ENV che contiene le variabili di ambiente, cui si accede indicando il nome della variabile come chiave.

4.4.1   Esempi

L'esempio seguente mostra un semplice array associativo e il modo di accedere ai suoi elementi in base alla chiave.

#!/usr/bin/perl

# Dichiarazione dell'array: attenzione a non fare confusione!
#             -------------    ----------------    ---------
%deposito = ("primo", "alfa", "secondo", "bravo", "terzo", 3);


# Emette il contenuto dei vari elementi.
print "$deposito{primo}\n";
print "$deposito{secondo}\n";
print "$deposito{terzo}\n";

Se il file si chiama 21.pl, si può verificare il suo funzionamento nel modo seguente:

chmod +x 21.pl[Invio]

21.pl[Invio]

alfa
bravo
3

---------

L'esempio seguente è identico al precedente, ma l'hash viene dichiarato in modo più facile da interpretare visivamente.

#!/usr/bin/perl

# Dichiarazione dell'array.
%deposito = (
        "primo", "alfa",
        "secondo", "bravo",
        "terzo", 3,
);

# Emette il contenuto dei vari elementi.
print "$deposito{primo}\n";
print "$deposito{secondo}\n";
print "$deposito{terzo}\n";

---------

L'esempio seguente è identico al precedente, ma l'hash viene dichiarato in modo ancora più leggibile.

#!/usr/bin/perl

# Dichiarazione dell'array.
%deposito = (
        primo   => "alfa",
        secondo => "bravo",
        terzo   => 3,
);

# Emette il contenuto dei vari elementi.
print "$deposito{primo}\n";
print "$deposito{secondo}\n";
print "$deposito{terzo}\n";

---------

L'esempio seguente mostra l'uso dell'array %ENV per la lettura delle variabili di ambiente.

#!/usr/bin/perl

print "PATH: $ENV{PATH}\n";
print "TERM: $ENV{TERM}\n";

Se il file si chiama 24.pl, si può verificare il suo funzionamento nel modo seguente:

chmod +x 24.pl[Invio]

24.pl[Invio]

PATH: /usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin
TERM: linux

4.5   Operatori ed espressioni

Il sistema di operatori e delle relative espressioni che possono essere create con Perl è piuttosto complesso. La parte più consistente di questa gestione riguarda il trattamento delle stringhe, che qui verrà descritto particolarmente in un altro capitolo. Alcuni tipi di espressioni e i relativi operatori non vengono mostrati, data la loro complessità per chi non conosca già il linguaggio C. In particolare viene saltata la gestione dei dati a livello di singoli bit.

Il senso e il risultato di un'espressione dipende dal contesto. La valutazione di un'espressione dipende dalle precedenze che esistono tra i vari tipi di operatori. Si parla di precedenza superiore quando qualcosa viene valutato prima di qualcos'altro, mentre la precedenza è inferiore quando qualcosa viene valutato dopo qualcos'altro.

4.5.1   Operatori che intervengono su valori numerici, stringhe e liste

Gli operatori che intervengono su valori numerici sono elencati nella tabella 4.3.

Operatore e operandi Descrizione
++ opIncrementa di un'unità l'operando prima che venga restituito il suo valore.
op ++ Incrementa di un'unità l'operando dopo averne restituito il suo valore.
-- opDecrementa di un'unità l'operando prima che venga restituito il suo valore.
op -- Decrementa di un'unità l'operando dopo averne restituito il suo valore.
+ opNon ha alcun effetto.
- opInverte il segno dell'operando.
op1  +  op2Somma i due operandi.
op1  -  op2Sottrae dal primo il secondo operando.
op1  *  op2Moltiplica i due operandi.
op1  /  op2Divide il primo operando per il secondo.
op1  %  op2Modulo: il resto della divisione tra il primo e il secondo operando.
op1  **  op2Eleva il primo operando alla potenza del secondo.
var  =  valoreAssegna alla variabile il valore alla destra.
op1  +=  op2op1  =  op1  +  op2
op1  -=  op2op1  =  op1  -  op2
op1  *=  op2op1  =  op1  *  op2
op1  /=  op2op1  =  op1  /  op2
op1  %=  op2op1  =  op1  %  op2
op1  **=  op2op1  =  op1  **  op2
op1  ==  op2Vero se gli operandi si equivalgono.
op1  !=  op2Vero se gli operandi sono differenti.
op1  <  op2Vero se il primo operando è minore del secondo.
op1  >  op2Vero se il primo operando è maggiore del secondo.
op1  <=  op2Vero se il primo operando è minore o uguale al secondo.
op1  >=  op2Vero se il primo operando è maggiore o uguale al secondo.

Tabella 4.3. Elenco degli operatori utilizzabili in presenza di valori numerici. Le metavariabili indicate rappresentano gli operandi e la loro posizione.

La gestione da parte di Perl delle stringhe è molto sofisticata, e questa si attua principalmente attraverso gli operatori di delimitazione. In questa sezione si vuole solo accennare agli operatori che hanno effetto sulle stringhe, sorvolando su raffinatezze che si possono ottenere in casi particolari. La tabella 4.4 elenca tali operatori.

Operatore e operandi Descrizione
str1  .  str2Concatena le due stringhe.
str  x  numRestituisce la stringa ripetuta consecutivamente  num  volte.
str  =~  modelloCollega il modello alla stringa. Il risultato dipende dal contesto.
str  !~  modelloCome =~, ma restituisce un valore inverso.
var  =  valoreAssegna alla variabile il valore alla destra.
op1  x=  op2op1  =  op1  x  op2
op1  .=  op2op1  =  op1  .  op2
str1  eq  str2Vero se le due stringhe sono uguali.
str1  ne  str2Vero se le due stringhe sono differenti.
str1  lt  str2Vero se la prima stringa è lessicograficamente inferiore alla seconda.
str1  gt  str2Vero se la prima stringa è lessicograficamente superiore alla seconda.
str1  le  str2Vero se la prima stringa è lessicograficamente inferiore o uguale alla seconda.
str1  ge  str2Vero se la prima stringa è lessicograficamente superiore o uguale alla seconda.

Tabella 4.4. Elenco degli operatori utilizzabili in presenza di valori alfanumerici, o stringa. Le metavariabili indicate rappresentano gli operandi e la loro posizione.

Gli operatori che intervengono sulle liste sono elencati nella tabella 4.5.

Operatore e operandi Descrizione
lista  x  numRestituisce la lista composta ripetendo quella indicata per  num  volte.
array  =  listaCrea l'array assegnandogli la lista indicata alla destra.
elem1 ,  elem2La virgola è l'operatore di separazione degli elementi di una lista.
elem1  =>  elem2Sinonimo della virgola.
elem1  ..  elem2Rappresenta una lista di valori da  elem1  a  elem2 .

Tabella 4.5. Elenco degli operatori utilizzabili in presenza di liste. Le metavariabili indicate rappresentano gli operandi e la loro posizione.

4.5.2   Operatori logici

È il caso di ricordare che con Perl tutti i tipi di dati possono essere valutati in modo logico: lo zero numerico o letterale, la stringa nulla e un valore indefinito corrispondono a Falso, in tutti gli altri casi si considera equivalente a Vero. Gli operatori logici sono elencati nella tabella 4.6.

Operatore e operandi Descrizione
!  opInverte il risultato logico dell'operando.
op1  &&  op2Se il risultato del primo operando è Falso non valuta il secondo.
op1  ||  op2Se il risultato del primo operando è Vero non valuta il secondo.
op1  and  op2Come &&, ma con un livello di precedenza molto basso.
op1  or  op2Come ||, ma con un livello di precedenza molto basso.

Tabella 4.6. Elenco degli operatori logici. Le metavariabili indicate rappresentano gli operandi e la loro posizione.

Il risultato di un'espressione logica complessa è quello dell'ultima espressione elementare a essere valutata. Questo particolare è importante, anche se si tratta di un comportamento comune di diversi linguaggi, perché viene usato spesso per condizionare l'esecuzione di istruzioni, senza usare le strutture tradizionali, come if-else, o simili.

(5)

L'esempio seguente dovrebbe dare l'idea di come si può utilizzare l'operatore logico || (OR). Il risultato logico finale non viene preso in considerazione, quello che conta è solo il risultato della condizione $valore > 90, che se non si avvera fa sì che venga eseguita l'istruzione print posta come secondo operando.

#!/usr/bin/perl
...
$valore = 100;
...
$valore > 90 || print "Il valore è insufficiente\n";
...

In pratica, se il valore contenuto nella variabile $valore supera 90, si ottiene l'emissione del messaggio attraverso lo standard output. In questi casi, si usano preferibilmente gli operatori and e or, che si distinguono perché hanno una precedenza molto bassa, adattandosi meglio alla circostanza.

$valore > 90 or print "Il valore è insufficiente\n";

Come si vede dalla variante dell'esempio proposta, l'espressione diventa quasi simpatica, perché sembra una frase inglese più comprensibile. La cosa può diventare ancora più «divertente» se si utilizza la funzione interna die(), che serve a visualizzare un messaggio attraverso lo standard error e a concludere il funzionamento del programma Perl.

$valore > 90 or die "Il valore è insufficiente\n";

A parte la simpatia o il divertimento nello scrivere codice del genere, è bene ricordare che poi si tratta di qualcosa che un altro programmatore può trovare difficile da interpretare.

4.5.3   Operatori particolari

Tra gli operatori che non sono stati indicati nelle categorie descritte precedentemente, il più interessante è il seguente:

condizione  ?  espressione1  :  espressione2

Se la condizione restituisce il valore Vero, allora l'operatore restituisce il valore della prima espressione, altrimenti quello della seconda.

4.5.4   Raggruppamenti di espressioni

Le espressioni, di qualunque genere siano, possono essere raggruppate in modo che la loro valutazione avvenga in un ordine differente da quanto previsto dalle precedenze legate agli operatori utilizzati. Per questo si usano le parentesi tonde, come avviene di solito anche negli altri linguaggi.

Le parentesi tonde sono anche i delimitatori delle liste, per cui è anche possibile immaginare che esistano delle liste contenenti delle espressioni. Se si valuta una lista di espressioni, si ottiene il risultato della valutazione dell'ultima di queste.

4.6   Strutture di controllo del flusso

Perl gestisce praticamente tutte le strutture di controllo di flusso degli altri linguaggi di programmazione, compreso go-to che comunque è sempre meglio non utilizzare, e qui non viene presentato volutamente.

Quando una struttura particolare controlla un gruppo di istruzioni, queste vengono necessariamente delimitate attraverso le parentesi graffe, come avviene in C, ma a differenza di quel linguaggio, non è possibile farne a meno quando ci si limita a indicare una sola istruzione.

Le strutture di controllo del flusso basano normalmente questo controllo sulla verifica di una condizione espressa all'interno di parentesi tonde.

Nei modelli sintattici indicati, le parentesi graffe fanno parte delle istruzioni, essendo i delimitatori dei blocchi di istruzioni di Perl.

4.6.1   if | unless

if ( condizione ) {  istruzione ;...}
if ( condizione ) {  istruzione ;...} else {  istruzione ;...}
if ( cond ) {  istr ;...} elsif ( cond ) {  istr ;...}... else {  istr ;...}

Se la condizione si verifica viene eseguito il gruppo di istruzioni seguente, racchiuso tra parentesi graffe, quindi il controllo passa alle istruzioni successive alla struttura. Se viene utilizzato elsif, nel caso non si verifichino altre condizioni precedenti, viene verificata la condizione successiva, e se questa si avvera, viene eseguito il gruppo di istruzioni che ne segue. Al termine il controllo riprende dopo la struttura. Se viene utilizzato else, quando non si verifica alcuna condizione di quelle poste, viene eseguito il gruppo di istruzioni finale. Seguono alcuni esempi.

if ($importo > 10000000) { print "L'offerta è vantaggiosa"; }

---------

if ($importo > 10000000)
  {
    $memorizza = $importo;
    print "L'offerta è vantaggiosa.\n";
  }
else
  {
    print "Lascia perdere.\n";
  }

---------

if ($importo > 10000000)
  {
    $memorizza = $importo;
    print "L'offerta è vantaggiosa.\n";
  }
elsif ($importo > 5000000)
  {
    $memorizza = $importo;
    print "L'offerta è accettabile.\n";
  }
else
  {
    print "Lascia perdere.\n";
  }

unless può essere utilizzato come if, con la differenza che la condizione viene valutata in modo opposto, cioè viene eseguito il gruppo di istruzioni che segue unless solo se non si verifica la condizione.

4.6.2   while | until

while ( condizione ) {  istruzione ;...}
while ( condizione ) {  istruzione ;...} continue {  istruzione ;...;}

La struttura while esegue un gruppo di istruzioni finché la condizione restituisce il valore Vero. La condizione viene valutata prima di eseguire il gruppo di istruzioni e poi ogni volta che termina un ciclo, prima dell'esecuzione del successivo.

Il blocco di istruzioni che segue continue viene eseguito semplicemente di seguito al gruppo normale. Ci sono situazioni in cui viene saltato. Segue l'esempio del calcolo del fattoriale.

#!/usr/bin/perl

# Il numero di partenza viene fornito come argomento nella riga di comando.
$numero = $ARGV[0];
$cont = $numero -1;
while ($cont > 0)
  {
    $numero = $numero * $cont;
    $cont = $cont -1;
  }
print "Il fattoriale è $numero.\n";

La stessa cosa si poteva semplificare nel modo seguente:

#!/usr/bin/perl

# Il numero di partenza viene fornito come argomento nella riga di comando.
$numero = $ARGV[0];
$cont = $numero -1;
while ($cont)
  {
    $numero *= $cont;
    $cont--;
  }
print "Il fattoriale è $numero.\n";

All'interno delle istruzioni di un ciclo while possono apparire alcune istruzioni particolari:

L'esempio seguente è una variante del calcolo del fattoriale in modo da vedere il funzionamento di last. while (1){...} equivale a un ciclo senza fine perché la condizione (cioè il valore 1) è sempre vera.

#!/usr/bin/perl

# Il numero di partenza viene fornito come argomento nella riga di comando.
$numero = $ARGV[0];
$cont = $numero -1;
# Il ciclo seguente è senza fine.
while (1)
  {
    $numero *= $cont;
    $cont--;
    if (!$cont)
      {
        last;
      }
  }
print "Il fattoriale è $numero.\n";

until può essere utilizzato come while, con la differenza che la condizione viene valutata in modo opposto, cioè viene eseguito il gruppo di istruzioni che segue until solo se non si verifica la condizione. In pratica, al verificarsi della condizione, il ciclo termina.

4.6.3   do ... while | do ... until

do {  istruzione ;...} while ( condizione )

do...while esegue un gruppo di istruzioni almeno una volta, quindi ne ripete l'esecuzione finché la condizione restituisce il valore Vero. Segue il solito esempio del calcolo del fattoriale.

#!/usr/bin/perl

# Il numero di partenza viene fornito come argomento nella riga di comando.
$cont       = $ARGV[0];
$fattoriale = 1;
do
  {
    $fattoriale *= $cont;
    $cont--;
  }
while ($cont);
print "Il fattoriale è $fattoriale.\n";

until, al posto di while, verifica che la condizione non si avveri, in pratica inverte il senso della condizione che controlla il ciclo.

4.6.4   for

for ( espressione1 ;  espressione2 ;  espressione3 ) {  istruzione ;...}

Questa è la forma tipica di un'istruzione for, in cui la prima espressione corrisponde all'assegnamento iniziale di una variabile, la seconda a una condizione che deve verificarsi fino a che si vuole che sia eseguito il gruppo di istruzioni e la terza all'incremento o decremento della variabile inizializzata con la prima espressione. In pratica, potrebbe esprimersi nella sintassi seguente:

for ($ var  =  n  ;  condizione ; $ var ++) {  istruzione ;...}

In realtà la forma del ciclo for potrebbe essere diversa, ma in tal caso si preferisce utilizzare il nome foreach che è comunque un sinonimo.

In breve: la prima espressione viene eseguita una volta sola all'inizio del ciclo; la seconda viene valutata all'inizio di ogni ciclo e il gruppo di istruzioni viene eseguito solo se il risultato è Vero. L'ultima espressione viene eseguita alla fine dell'esecuzione del gruppo di istruzioni, prima che si ricominci con l'analisi della condizione.

Segue il solito esempio del calcolo del fattoriale.

#!/usr/bin/perl

# Il numero di partenza viene fornito come argomento nella riga di comando.
$numero = $ARGV[0];
for ($cont = 1; $cont < $ARGV[0]; $cont++)
  {
    $numero *= $cont;
  }
print "Il fattoriale è $numero.\n";

4.6.5   foreach

foreach  var_scalare   lista  {  istruzione ;...}

foreach è un sinonimo di for, per cui si tratta della stessa cosa, solo che si preferisce utilizzare due termini differenti per una struttura che può articolarsi in due modi diversi.

La variabile scalare iniziale, viene posta di volta in volta ai valori contenuti nella lista, e ogni volta viene eseguito il gruppo di istruzioni. Il ciclo finisce quando non ci sono più elementi nella lista.

Segue il solito esempio del calcolo del fattoriale.

#!/usr/bin/perl

# Il numero di partenza viene fornito come argomento nella riga di comando.
$numero = $ARGV[0];
foreach $cont (1 .. ($ARGV[0] -1))
  {
    $numero *= $cont;
  }
print "Il fattoriale è $numero.\n";

4.6.6   Istruzioni condizionate

Una brutta tradizione di Perl consente la scrittura di istruzioni condizionate secondo le sintassi seguenti:

espressione1  if  espressione2
espressione1  unless  espressione2
espressione1  while  espressione2
espressione1  until  espressione2

Si tratta di forme abbreviate e sconsigliabili (secondo il parere di chi scrive) delle sintassi seguenti.

if ( espressione2 ) {  espressione1  }
unless ( espressione2 ) {  espressione1  }
while ( espressione2 ) {  espressione1  }
until ( espressione2 ) {  espressione1  }

Come si vede, lo sforzo necessario a scrivere le istruzioni nel modo normale, è minimo. Evidentemente, l'idea che sta alla base della possibilità di usare sintassi così strane delle strutture if, while e simili, è quella di permettere la scrittura di codice che assomigli alla lingua inglese.

4.7   Funzioni interne

Perl fornisce una serie di funzioni già pronte. In realtà, più che di funzioni vere e proprie, si tratta di operatori unari che intervengono sull'argomento posto alla loro destra. Questa precisazione è importante perché serve a comprendere meglio il meccanismo con cui Perl interpreta le chiamate di tali funzioni od operatori.

Finora si è visto il funzionamento di una funzione molto semplice, print. Questa emette il risultato dell'operando che si trova alla sua destra, ma solo del primo. Se ciò che appare alla destra di print è un'espressione, la valutazione dell'insieme print  espressione, dipende dalle precedenze tra gli operandi. Infatti:

print 1+2+4;

restituisce sette;

print (1+2)+4;

restituisce tre;

print (1+2+4);

restituisce sette.

Utilizzando le funzioni di Perl nello stesso modo in cui si fa negli altri linguaggi, racchiudendo l'argomento tra parentesi, si evitano ambiguità; soprattutto, in questo modo, sembrano essere veramente funzioni anche se si tratta di operatori.

L'argomento di queste funzioni di Perl (ovvero l'operando) può essere uno scalare o una lista. In questo caso quindi, così come lo scalare non ha la necessità di essere racchiuso tra parentesi, anche la lista non lo ha. Resta in ogni caso il fatto che ciò sia almeno consigliabile per migliorare la leggibilità del programma. Il capitolo 7 elenca e descrive alcune di queste funzioni.

4.8   Input/Output dei dati

L'I/O può avvenire sia attraverso l'uso dei flussi standard di dati (standard input, standard output e standard error) che utilizzando file differenti. I flussi di dati standard sono trattati come file normali, con la differenza che generalmente non devono essere aperti o chiusi.

Assieme alla gestione dei file si affianca la possibilità di eseguire comandi del sistema operativo, in parte descritta nella sezione dedicata agli operatori di delimitazione di stringhe.

4.8.1   Esecuzione di comandi di sistema

Una stringa racchiusa tra apici inversi, oppure indicata attraverso l'operatore di stringa qx, viene interpolata e il risultato viene fatto eseguire dal sistema operativo.

L'output del comando è il risultato della valutazione della stringa, e il valore restituito dal comando può essere letto dalla variabile predefinita $?. È importante ricordare che generalmente i comandi del sistema operativo restituiscono un valore pari a zero quando l'operazione ha avuto successo. Dal punto di vista di Perl, quando $? contiene il valore Falso significa che il comando ha avuto successo.

L'esempio seguente dovrebbe rendere l'idea.

#!/usr/bin/perl

# $elenco riceve l'elenco di file in forma di un'unica stringa.
$elenco = `ls *.pl`;

if ($? == 0)
  {
    # L'operazione ha avuto successo e viene visualizzato l'elenco.
    print "$elenco\n";
  }
else
  {
    # L'operazione è fallita.
    print "Non ci sono programmi Perl\n";
  }

4.8.2   Gestione dei file

Perl, come molti altri linguaggi, gestisce i file come flussi, o file handle, che sono un riferimento interno a un file aperto. I flussi di file vengono indicati attraverso un nome, che per convenzione è espresso quasi sempre attraverso lettere maiuscole.

Perl mette a disposizione tre flussi di file predefiniti: STDIN, STDOUT e STDERR. Questi corrispondono rispettivamente ai flussi di standard input, standard output e standard error. Altri file possono essere utilizzati aprendoli attraverso la funzione open(), con cui si abbina un flusso al file reale.

Perl è predisposto per gestire agevolmente i file di testo, cioè quelli organizzati convenzionalmente in righe terminanti con il codice di interruzione di riga. Si valuta un flusso di file, come se si trattasse di una variabile, racchiudendone il nome tra parentesi angolari, e si ottiene la lettura e la restituzione di una riga, ogni volta che avviene tale valutazione. Per esempio,

#!/usr/bin/perl

while (defined ($riga = <STDIN>))
 {
    print $riga;
 }

emette attraverso lo standard output ciò che riceve dallo standard input. Quindi, la lettura del flusso di file attraverso la semplice valutazione dell'espressione, restituisce una riga fino al codice di interruzione di riga incluso. In questo modo, nell'esempio non è necessario aggiungere il codice \n nell'argomento della funzione print.

Se un flusso di file è l'unica cosa che appare nella condizione di un ciclo while o for, la sua valutazione genera la lettura della riga e il suo inserimento all'interno della variabile predefinita $_. Questo fatto può essere usato convenientemente considerando che quando si raggiunge la fine, la valutazione del flusso di file genera un valore indefinito, pari a Falso in una condizione. I due esempi seguenti sono identici al quello mostrato poco sopra.

#!/usr/bin/perl

while (<STDIN>)
  {
    print $_;
  }

---------

#!/usr/bin/perl

for ( ; <STDIN>; )
  {
    print $_;
  }

Un flusso di file può essere valutato in un contesto lista. In tal caso restituisce tutto il file in una lista in cui ogni elemento è una riga. Naturalmente ciò viene fatto a spese della memoria di elaborazione.

#!/usr/bin/perl

@mio_file = <STDIN>;
print @mio_file;

L'esempio appena mostrato si comporta come gli altri visti finora: restituisce lo standard input attraverso lo standard output.

(6)

4.8.3   File globbing

Perl, se non riconosce ciò che trova all'interno di parentesi angolari come un flusso di file, tratta questo come un modello per indicare nomi di file, e valutando un'entità del genere si ottiene l'elenco dei nomi corrispondenti. In pratica, la valutazione di <*.pl> restituisce l'elenco dei nomi dei file che terminano con l'estensione .pl nella directory corrente. Generalmente è preferibile eseguire un tipo di valutazione del genere in un contesto lista, come nell'esempio seguente:

#!/usr/bin/perl

@mioelenco = <*.pl>;
print "@mioelenco\n";

In alternativa si può utilizzare la funzione interna glob(), come nell'esempio seguente:

#!/usr/bin/perl

@mioelenco = glob ("*.pl");
print "@mioelenco\n";

4.9   Funzioni definite dall'utente

Le funzioni definite dall'utente, o subroutine se si preferisce il termine, possono essere collocate in qualunque parte del sorgente Perl. Eventualmente possono anche essere caricate da file esterni. I parametri delle funzioni vengono passati nello stesso modo in cui si fa per le funzioni predefinite, interne a Perl: attraverso una lista di elementi scalari. Le funzioni ottengono i parametri dall'array predefinito @_. Il valore restituito dalle funzioni è quello dell'ultima istruzione eseguita all'interno della funzione, e solitamente si tratta di return che permette di controllare meglio la cosa.

La sintassi normale per la dichiarazione di una funzione è la seguente. Le parentesi graffe vanno intese in modo letterale e non fanno parte della descrizione del modello sintattico.

sub  nome  {  istruzione ... }

Per la chiamata di una funzione si deve usare la forma seguente:

& nome  ( parametro ,...)

L'uso della e-commerciale (&) all'inizio del nome è opportuno anche se non è strettamente obbligatorio: permette di evitare ambiguità se il nome della funzione è stato usato per altri tipi di entità all'interno del programma Perl.

#!/usr/bin/perl

sub somma
{
    return ($_[0] + $_[1]);
}

# I valori da sommare vengono indicati nella riga di comando.
$totale = &somma ($ARGV[0], $ARGV[1]);

print "$ARGV[0] + $ARGV[1] = $totale\n";

L'esempio mostrato sopra dovrebbe chiarire il ruolo dell'array @_ all'interno della funzione, come mezzo per il trasporto dei parametri di chiamata.

4.9.1   Chiamata per riferimento e chiamata per valore

L'array @_ è costruito attraverso riferimenti ai parametri utilizzati originariamente nella chiamata. Ciò è sufficiente a fare in modo che modificando il contenuto dei suoi elementi, queste modifiche si riflettano sui parametri di chiamata. Si ha in tal modo quello che si definisce chiamata per riferimento, in cui la funzione è in grado di modificare le variabili utilizzate come parametri.

Naturalmente ciò ha senso solo se i parametri utilizzati sono espressi in forma di variabile e come tali possono essere modificati. Tentare di modificare una costante produce un errore irreversibile.

Dal momento che l'array @_ contiene riferimenti ai dati originali, assegnando all'array un'altra lista di valori non si alterano i dati originali, ma si perde il contatto con quelli. Quindi, non si può assegnare a tale array una lista come modo rapido di variare tutti i parametri della chiamata.

Per gestire elegantemente una funzione che utilizzi il sistema della chiamata per valore, si può fare come nell'esempio seguente:

sub miasub
{
        local ($primo, $secondo, $terzo) = @_;
        ...
        return ...;
}

In tal modo, agendo successivamente solo sulle variabili scalari ottenute non si modifica l'array @_, e lo stesso codice diventa più leggibile.

4.9.2   Campo di azione delle variabili

Perl gestisce tre tipi di campi di azione per le variabili (di solito si usa il termine scope per fare riferimento a questo concetto). Si tratta di variabili pubbliche, private e locali.

Le variabili pubbliche sono accessibili in ogni punto del programma, senza alcuna limitazione, a meno che vengano oscurate localmente. Si ottiene una variabile pubblica quando questa viene creata senza specificare nulla di particolare.

# Inizializzazione di una variabile pubblica.
$pubblica = "ciao";

Una variabile privata è visibile solo all'interno del blocco di istruzioni in cui viene creata e dichiarata come tale. Le funzioni chiamate eventualmente all'interno del blocco, non possono accedere alle variabili private dichiarate nel blocco chiamante. Si dichiara una variabile privata attraverso l'istruzione my.

my  variabile
my  variabile  =  valore
my ( variabile1 ,  variabile2 , ...)

Una variabile locale è visibile solo all'interno del blocco di istruzioni in cui viene creata e dichiarata come tale. Le funzioni chiamate eventualmente all'interno del blocco, possono accedere alle variabili locali dichiarate nel blocco chiamante. Si dichiara una variabile locale attraverso l'istruzione local.

local  variabile
local  variabile  =  valore
local ( variabile1 ,  variabile2 , ...)

Sia le variabili private che quelle locali permettono di utilizzare un nome già esistente a livello globale, sovrapponendosi temporaneamente a esso. Quelle locali, in particolare, hanno valore anche per le funzioni chiamate all'interno dei blocchi in cui queste variabili sono state dichiarate.

Si dice anche che le variabili private abbiano un campo di azione definito in modo lessicale, mentre quelle locali in modo dinamico: terminata la zona di influenza, le variabili locali vengono rilasciate, mentre quelle private no.

Seguono due esempi di calcolo del fattoriale in modo ricorsivo. In un caso si utilizza una variabile privata, nell'altro una locale. Funzionano entrambi correttamente.

#!/usr/bin/perl

sub fattoriale
{
    my $valore = $_[0];
    if ($valore > 1)
      {
        return ($valore * &fattoriale ($valore -1));
      }
    else
      {
        return 1;
      }
}

$miofatt = &fattoriale ($ARGV[0]);

print "$ARGV[0]! = $miofatt\n";

---------

#!/usr/bin/perl

sub fattoriale
{
    local $valore = $_[0];
    if ($valore > 1)
      {
        return ($valore * &fattoriale ($valore -1));
      }
    else
      {
        return 1;
      }
}

$miofatt = &fattoriale ($ARGV[0]);

print "$ARGV[0]! = $miofatt\n";

4.10   Variabili contenenti riferimenti

Si è accennato al fatto che una variabile scalare può contenere anche riferimenti, oltre a valori stringa o numerici. Il riferimento è un modo alternativo per puntare a un'entità determinata del programma. La gestione di questi riferimenti da parte di Perl è piuttosto complessa. Qui vengono analizzate solo alcune caratteristiche e possibilità.

Perl gestisce due tipi di riferimenti: diretti (hard) e simbolici. Volendo fare un'analogia con quello che accade con i collegamenti dei file system Unix, i primi sono paragonabili ai collegamenti fisici (gli hard link), mentre i secondi sono simili ai collegamenti simbolici.

4.10.1   Riferimenti diretti

I riferimenti diretti vengono creati utilizzando l'operatore barra obliqua inversa (\), come negli esempi seguenti.

$rifscalare     = \$mioscalare;

$rifarray       = \@mioarray;

$rifhash        = \%miohash;

$rifcodice      = \&miafunzione;

$rifflusso      = \*MIO_FILE;

Esiste anche una forma sintattica alternativa di esprimere i riferimenti: si tratta di indicare il nome dell'entità per la quale si vuole creare il riferimento, preceduto da un asterisco e seguito dalla definizione del tipo a cui questa entità appartiene, tra parentesi graffe.

$rifscalare     = *mioscalare{SCALAR};

$rifarray       = *mioarray{ARRAY};

$rifhash        = *miohash{HASH};

$rifcodice      = *miafunzione{CODE};

$rifflusso      = *MIO_FILE{IO};

Perl riconosce anche il tipo FILEHANDLE equivalente a IO, per motivi di compatibilità con il passato.

4.10.2   Riferimenti simbolici

I riferimenti simbolici sono basati sul nome dell'entità a cui si riferiscono, per cui, una variabile scalare contenente il nome dell'oggetto può essere gestita come un riferimento simbolico. Seguono alcuni degli esempi visti nel caso dei riferimenti diretti, in quanto con questo tipo di riferimenti non si possono gestire tutte le situazioni.

$rifscalare = 'mioscalare';

$rifarray   = 'mioarray';

$rifhash    = 'miohash';

$rifcodice  = 'miafunzione';

Generalmente, l'utilizzo di riferimenti simbolici è sconsigliabile, a meno che ci sia una buona ragione.

4.10.3   Dereferenziazione

Restando in questi termini, a parte il caso dei flussi di file, il modo per dereferenziare le variabili che contengono i riferimenti è uguale per entrambi i tipi. La forma normale richiede l'utilizzo delle parentesi graffe per delimitare lo scalare. In precedenza si era visto che una variabile scalare poteva essere indicata attraverso la forma ${ nome }. Estendendo questo concetto, racchiudendo tra parentesi graffe un riferimento, si ottiene l'oggetto stesso. Per cui:

${$rifscalare}

equivale a utilizzare $mioscalare;

${$rifscalare}[0]

equivale a utilizzare $mioarray[0];

${$rifhash}{primo}

equivale a utilizzare $miohash{primo};

&{$rifcodice} (1, 7)

equivale a utilizzare &miafunzione (1, 7).

Sono anche ammissibili altre forme, più espressive o più semplici. La tabella 4.7 riporta alcuni esempi con le forme possibili per dereferenziare gli scalari contenenti dei riferimenti.

${$rifscalare} $$rifscalare
${$rifscalare}[0] $$rifscalare[0] $rifscalare->[0]
${$rifhash}{primo} $$rifhash{primo} $rifhash->{primo}
&{$rifcodice} (1, 7) &$rifcodice (1, 7) $rifcodice-> (1, 7)

Tabella 4.7. Esempi attraverso cui dereferenziare le variabili scalari contenenti dei riferimenti.

Il caso dei flussi di file è più semplice, in quanto è sufficiente valutare il riferimento, invece del flusso di file vero e proprio. L'esempio seguente dovrebbe chiarire il meccanismo.

$rifstdio  = \*STDIO;
$riga = <$rifstdio>;

4.10.4   Array multidimensionali

Gli array di Perl hanno una sola dimensione. Per ovviare a questo inconveniente si possono utilizzare elementi che fanno riferimento ad altri array. In pratica, si potrebbe fare qualcosa di simile all'esempio seguente:

@primo   = (1, 2);
@secondo = (3, 4);

@mioarray = (\@primo, \@secondo);

Qui, l'array mioarray rappresenta una matrice a due dimensioni rappresentabile nel modo seguente:

/ 1  2 \
|      |
\ 3  4 /

Per accedere a un elemento singolo di questo array, per esempio al primo elemento della seconda riga (il numero tre), si può usare intuitivamente una di queste due forme.

${$mioarray[1]}[0]

$mioarray[1]->[0]

In alternativa è concessa anche la forma seguente, più semplice e simile a quella di altri linguaggi.

$mioarray[1][0]

Una particolarità di Perl sta nella possibilità di definire delle entità anonime. Solitamente si tratta di variabili che non hanno un nome e a cui si accede attraverso uno scalare contenente un riferimento diretto al loro contenuto. Il caso più interessante è dato dagli array, perché questa possibilità permette di definire istantaneamente un array multidimensionale. L'array dell'esempio precedente poteva essere dichiarato nel modo seguente:

@mioarray = ([1, 2], [3, 4]);

La gestione pratica di un array multidimensionale secondo Perl, potrebbe sembrare un po' complessa a prima vista. Tuttavia, basta ricordare che si tratta di array dinamici, per cui, basta assegnare un elemento per dichiararlo implicitamente:

@mio_array = ();
...
$mio_array[0] = "ciao";
$mio_array[1] = "come";
$mio_array[2] = "stai";
...

Come si vede, viene dichiarato l'array senza elementi, al quale questi vengono inseriti solo successivamente. Così facendo, la dimensione dell'array varia in base all'uso che se ne fa. Con questo criterio si possono gestire anche gli array multimediali:

@mio_array = ();
...
$mio_array[0] = ();
...
$mio_array[0][0] = "ciao";
$mio_array[0][1] = "come";
$mio_array[0][2] = "stai";
...

In questo caso, dopo aver dichiarato l'array @mio_array, senza elementi, viene dichiarato il primo elemento come contenente un altro array vuoto; infine, vengono dichiarati i primi tre elementi di questo sotto-array. Il funzionamento dovrebbe essere intuitivo, anche se si tratta effettivamente di un meccanismo molto complesso e potente.

Di fronte a array multidimensionali di questo tipo, potenzialmente irregolari, si può porre il problema di conoscere la lunghezza di un sotto-array. Volendo usare la tecnica del prefisso $#, si potrebbe fare come nell'esempio seguente, per determinare la lunghezza dell'array contenuto in $mio_array[0].

$ultimo = $#{$mio_array[0]};

4.10.5   Alias

Attraverso l'uso dei riferimenti, è possibile creare un alias di una variabile. Per comprendere questo è necessario introdurre l'uso dell'asterisco. Si osservi questo esempio: se $variabile rappresenta una variabile scalare, *variabile rappresenta il puntatore alla variabile omonima. In un certo senso, *variabile è equivalente a \$variabile, ma non è proprio la stessa cosa. Si osservino gli assegnamenti seguenti, supponendo che esista già la variabile $tua e si tratti di uno scalare.

*mia = \$tua;
*mia = *tua;

I due assegnamenti sono identici, perché in entrambi i casi si assegna a *mia il riferimento alla variabile scalare $tua. Il risultato di questo è che si può usare la variabile scalare $mia come alias di $tua. L'esempio seguente dovrebbe chiarire meglio la cosa.

#!/usr/bin/perl
$tua = "ciao";
*mia = \$tua;
print "$mia\n";

Quello che si ottiene è l'emissione della stringa ciao, cioè il contenuto della variabile $tua, ottenuto attraverso l'alias $mia.

Attraverso gli alias è possibile gestire agevolmente il passaggio di parametri per riferimento nelle chiamate delle funzioni. Si osservi l'esempio seguente, in cui una funzione altera il contenuto di un array, senza che questo debba essere dichiarato come variabile globale.

#!/usr/bin/perl
sub alterazione_array
{
  local (*a) = $_[0];
  $a[0] = 1;
  $a[1] = 2;
}

local ($b) = ();

$b[0] = 9;
$b[1] = 8;
$b[2] = 7;

&alterazione_array (\@b);

print STDOUT ($a1[0] . " " . $a1[1] . " " . $a1[2] . "\n");

Eseguendo questo programmino molto semplice, si ottiene la stringa seguente:

1 2 7

Questo serve a dimostrare che i primi due elementi dell'array sono stati modificati dalla funzione.

4.11   Avvio di Perl

Normalmente è sufficiente rendere eseguibile uno script Perl per fare in modo che il programma /usr/bin/perl venga eseguito automaticamente per la sua interpretazione. Il programma /usr/bin/perl permette di utilizzare alcune opzioni, principalmente utili per individuare errori sintattici e problemi di altro tipo.

Alcune opzioni
-c

Analizza sintatticamente lo script e termina senza eseguirlo.

-w

Viene usato assieme a -c e permette di avere informazioni più dettagliate su problemi eventuali che non sono necessariamente considerabili come errori sintattici.

-d

Esegue lo script all'interno di un sistema diagnostico di debug.

Esempi

perl mio.pl

Avvia il programma Perl mio.pl. Generalmente si avvia direttamente lo script, ma se questo non è stato reso eseguibile attraverso i permessi, si può ovviare in questo modo.

perl -c mio.pl

Analizza lo script mio.pl senza eseguirlo. Se tutto va bene si ottiene l'output seguente:

mio.pl syntax OK

perl -c -w mio.pl

Come nell'esempio precedente, con l'aggiunta dell'opzione -w, con la quale si ottengono maggiori indicazioni e suggerimenti per migliorare il programma.

perl -d mio.pl

Avvia il sistema diagnostico per il programma mio.pl.

Informatica per il commercio elettronico 2000.11.04 --- Copyright © 2000 Daniele Giacomini --  daniele @ swlibero.org

1) L'utilizzo del dollaro come prefisso dei nomi delle variabili assomiglia a quanto si fa con le shell derivate da quella di Bourne, con la differenza che con Perl il dollaro si lascia sempre, mentre con queste shell si utilizza solo quando si deve leggere il loro contenuto.

2) Se una stringa viene interrotta e ripresa nella riga successiva, quello che si ottiene, nel punto dell'interruzione, è l'inserimento di un codice di interruzione di riga. In pratica, lo stesso codice di interruzione di riga utilizzato per andare a capo, viene inserito nella stringa e trattato esattamente per quello che è.

3) In pratica, quando si fa riferimento a un solo elemento di un array si può immaginare che si tratti di un gruppo di elementi composto da un solo elemento, per cui si può utilizzare il prefisso @ anche in questo caso.

4) Meglio non modificare questa variabile.

5) Questo tipo di approccio da parte del programmatore è sconsigliabile in generale, dato che serve a complicare la lettura e l'interpretazione umana del sorgente; tuttavia è importante conoscere esempi di questo tipo, perché sono sempre molti i programmi fatti alla svelta senza pensare alla leggibilità.

6) La funzione print ha l'argomento senza virgolette perché altrimenti inserirebbe uno spazio indesiderato tra un elemento e l'altro.


Dovrebbe essere possibile fare riferimento a questa pagina anche con il nome perl_introduzione.html

[successivo] [precedente] [inizio] [fine] [indice generale] [indice analitico]