Cos'è Perl e perché è ancora nei sistemi Unix
Cos'è Perl: il linguaggio nato per elaborare testo, le regex integrate che hanno fatto scuola, la fama di codice illeggibile e dove lo incontri ancora oggi.
Apri un server Linux ereditato da chi c'era prima di te, cerchi lo script che ogni notte genera il report dei log e trovi un file .pl pieno di simboli: $_, @ARGV, =~ s/^\s+//. Nessuno in ufficio sa bene cosa faccia, ma funziona da anni e nessuno osa toccarlo. In questo articolo trovi cos'è Perl, perché è ovunque nei sistemi Unix e cosa ti serve sapere per leggerlo senza panico.
Cos'è Perl
Perl è un linguaggio di scripting interpretato creato da Larry Wall alla fine degli anni Ottanta per estrarre informazioni da file di testo e generare report, diventato poi per anni lo strumento universale dei sistemisti Unix e il linguaggio con cui si scriveva buona parte del primo web dinamico.
Il nome viene spesso letto come acronimo di "Practical Extraction and Report Language", e la definizione è onesta: Perl nasce per prendere testo disordinato (log, file di configurazione, output di altri programmi) e trasformarlo in qualcosa di utile. Tutto il resto è venuto dopo.
Quando si parla di Perl oggi si intende quasi sempre Perl 5, la versione che gira sui server da decenni e che continua a ricevere nuove release. Il perché di questa precisazione lo vediamo più avanti.
Il nastro adesivo di Unix
Negli anni Novanta un sistemista aveva a disposizione la shell e una manciata di strumenti specializzati: grep per cercare, sed per sostituire, awk per elaborare colonne. Ognuno bravo in una cosa, ma combinarli per compiti un po' più complessi diventava presto un groviglio di pipe e di quoting.
Perl ha preso il meglio di tutti quegli strumenti e li ha messi in un unico linguaggio vero, con variabili, funzioni, strutture dati. Per questo veniva chiamato "il nastro adesivo di Internet": serviva a tenere insieme sistemi che non erano stati pensati per parlarsi.
Il secondo capitolo è il web. Quando le pagine dinamiche si generavano con gli script CGI (il server web lanciava un programma per ogni richiesta e ne restituiva l'output come pagina), Perl era la scelta naturale: era già installato, trattava il testo meglio di chiunque, e produrre HTML è, in fondo, generare un report. Moduli di form, contatori di visite, guestbook: moltissimi siti di quegli anni avevano una cartella cgi-bin piena di file .pl.
Ecco il tipo di compito per cui Perl è ancora imbattibile in poche righe: contare le richieste per indirizzo IP in un log di un server web.
#!/usr/bin/perl
use strict;
use warnings;
my %richieste;
while (my $riga = <STDIN>) {
# l'IP è il primo campo della riga
if ($riga =~ /^(\d+\.\d+\.\d+\.\d+)\s/) {
$richieste{$1}++;
}
}
for my $ip (sort { $richieste{$b} <=> $richieste{$a} } keys %richieste) {
print "$ip\t$richieste{$ip}\n";
}
Lo lanci con perl conta.pl < access.log e ottieni la classifica. Lettura riga per riga, espressione regolare, tabella associativa, ordinamento: tutto senza importare niente.
Le espressioni regolari dentro la sintassi
Questo è il contributo più duraturo di Perl, anche per chi non ne scriverà mai una riga.
In quasi tutti i linguaggi le espressioni regolari sono una libreria: chiami una funzione, le passi il pattern come stringa, ricevi un oggetto. In Perl sono parte della grammatica del linguaggio, con operatori dedicati:
my $testo = "Ordine 4521 spedito il 12/03";
if ($testo =~ /Ordine (\d+)/) {
print "Numero ordine: $1\n"; # le catture finiscono in $1, $2...
}
$testo =~ s/spedito/consegnato/; # sostituzione sul posto
=~ applica il pattern, m// cerca, s/// sostituisce, e i gruppi catturati compaiono in variabili speciali. Perl ha inoltre esteso le regex classiche di Unix con molte comodità che oggi dai per scontate: scorciatoie come \d, \w, \s, quantificatori non avidi come .*?, lookahead, gruppi non catturanti.
Queste estensioni sono piaciute così tanto che sono state copiate ovunque. La libreria PCRE si chiama letteralmente "Perl Compatible Regular Expressions", e il dialetto di regex che usi in Python, JavaScript, PHP, Java o nel tuo editor è in larga parte figlio di quello di Perl. Se sai scrivere una regex, in un certo senso sai già un pezzo di Perl.
"C'è più di un modo per farlo"
Il motto ufficiale della comunità Perl è TMTOWTDI: There's More Than One Way To Do It. È l'esatto opposto della filosofia di Python, dove dovrebbe esserci un modo ovvio di fare ogni cosa.
L'idea di Larry Wall, che veniva dalla linguistica, era che un linguaggio di programmazione dovesse comportarsi come una lingua naturale: permettere scorciatoie, sottintesi, stili diversi a seconda di chi parla. È ciò che rende Perl estremamente espressivo e piacevole da scrivere quando lo conosci bene.
Il rovescio della medaglia è la sua reputazione di linguaggio "write-only": facile da scrivere, quasi impossibile da rileggere. Guarda questa riga, perfettamente idiomatica:
print for grep { !$visti{$_}++ } <>;
Stampa le righe in input eliminando i duplicati, mantenendo l'ordine. Per un esperto è elegante. Per chi deve correggere un bug alle due di notte è un enigma: ci sono una variabile implicita ($_), un hash usato come insieme, un post-incremento dentro una negazione e un operatore di lettura senza nome.
Il problema non è il linguaggio in sé: si può scrivere Perl chiarissimo. Il problema è che il linguaggio non ti obbliga a farlo, e in un team di dieci persone ognuno sceglie il suo modo. Dopo qualche anno il codice diventa un collage di stili.
Sigilli e contesto: lo scoglio vero
Chi arriva da altri linguaggi inciampa quasi sempre negli stessi due concetti.
I sigilli
In Perl ogni variabile ha davanti un simbolo, il sigillo, che dice che tipo di cosa stai maneggiando:
| Sigillo | Tipo | Esempio |
|---|---|---|
$ | scalare: un singolo valore | $nome = "Anna" |
@ | array: lista ordinata | @citta = ("Roma", "Milano") |
% | hash: tabella chiave-valore | %eta = (anna => 30) |
Fin qui semplice. La trappola è che il sigillo indica cosa ottieni, non cosa è la variabile:
my @citta = ("Roma", "Milano", "Torino");
print $citta[0]; # "Roma": un singolo elemento, quindi $
print @citta[0, 1]; # una fetta: più elementi, quindi @
$citta[0] con il dollaro davanti a un array sembra un errore di battitura. È invece la regola.
Il contesto scalare e lista
Il secondo concetto è ancora più insolito: la stessa espressione restituisce cose diverse a seconda di dove la usi.
my @nomi = ("Anna", "Luca", "Sara");
my $quanti = @nomi; # contesto scalare: 3, il numero di elementi
my ($primo) = @nomi; # contesto lista: "Anna", il primo elemento
Le parentesi intorno a $primo cambiano il risultato. Molte funzioni integrate si comportano così, e finché non hai interiorizzato il concetto di contesto il codice Perl ti sembrerà pieno di comportamenti casuali. Non lo sono: seguono regole precise, ma sono regole che nessun altro linguaggio diffuso ti ha insegnato.
Perl 6 e Raku: un linguaggio diverso
Per molti anni si è parlato di Perl 6 come del grande successore di Perl 5. Il progetto però ha finito per diventare un linguaggio profondamente diverso, non compatibile con il codice esistente, e con tempi di sviluppo molto lunghi.
Alla fine la comunità ha preso atto della situazione: Perl 6 è stato rinominato Raku ed è oggi un linguaggio a sé, con la sua comunità e i suoi strumenti. Perl 5 ha continuato la sua strada in modo indipendente.
La conseguenza pratica per te: se cerchi documentazione o librerie, "Perl" significa Perl 5. Il repository storico di moduli, CPAN, è enorme e riguarda quello. Raku è un progetto interessante ma di nicchia, e non è la versione nuova del Perl che trovi sul server.
Dove lo incontri oggi (e quando non sceglierlo)
Serve dirlo chiaramente: per uno script nuovo, oggi, quasi nessuno sceglie Perl. Per l'automazione semplice c'è lo scripting Bash, per tutto ciò che supera le cinquanta righe c'è Python, che ha preso il posto di Perl come linguaggio generalista di scripting grazie alla leggibilità e a un ecosistema molto più vivo.
Eppure Perl non è sparito. Lo incontri in tre situazioni tipiche:
| Situazione | Perché c'è Perl |
|---|---|
| Script di amministrazione esistenti | Scritti anni fa, funzionano, nessuno ha motivo di riscriverli |
| Bioinformatica storica | Per anni è stato il linguaggio di riferimento per elaborare sequenze genetiche, che sono testo |
| Strumenti di sistema | Diverse utility Unix e script di installazione dei pacchetti sono in Perl |
Il punto più concreto è l'ultimo: Perl è preinstallato su quasi ogni sistema Unix-like, perché altri componenti del sistema ne hanno bisogno. Alcuni comandi di Git, come git send-email, sono scritti in Perl. Questo significa che uno script Perl gira praticamente ovunque senza installare nulla, e che le one-liner da riga di comando restano utilissime:
# sostituisce "vecchio.server" con "nuovo.server" in tutti i file .conf, modificandoli sul posto
perl -pi -e 's/vecchio\.server/nuovo.server/g' *.conf
Per il lavoro quotidiano sul terminale, insieme ai comandi Linux essenziali, saper leggere Perl a questo livello è più utile di quanto sembri.
Errori comuni con Perl
Scrivere senza use strict e use warnings. Senza queste due righe Perl accetta variabili mai dichiarate e ignora silenziosamente molti errori. Un nome di variabile scritto male diventa una variabile nuova e vuota, e il bug salta fuori settimane dopo.
Confondere == ed eq. Perl distingue il confronto numerico (==, <, >) da quello tra stringhe (eq, lt, gt). Scrivere if ($nome == "Anna") confronta due numeri, e due stringhe non numeriche valgono entrambe zero: la condizione è vera per qualsiasi nome.
Ignorare il contesto. Assegnare un array a uno scalare aspettandosi il primo elemento, e ottenere invece la lunghezza. È l'errore numero uno di chi arriva da altri linguaggi.
Riscrivere tutto appena lo trovi. Uno script Perl che funziona da anni contiene spesso casi limite gestiti per esperienza. Prima di convertirlo in Python, capisci cosa fa e scrivi dei test sul suo output: lo stesso principio del refactoring incrementale vale anche qui.
Studiarlo come primo linguaggio. La libertà sintattica di Perl, senza basi solide, produce abitudini difficili da togliere. Impara prima un linguaggio più rigido e aggiungi Perl quando ti serve.
In sintesi
Perl è il linguaggio nato per elaborare testo e generare report, e per anni ha tenuto insieme i sistemi Unix e il primo web dinamico grazie agli script CGI.
La sua eredità più grande sono le espressioni regolari: integrate nella sintassi del linguaggio, estese con le comodità che oggi usi ovunque, e copiate da quasi tutti gli altri linguaggi attraverso PCRE.
La sua flessibilità è anche il suo limite: il motto "c'è più di un modo per farlo", i sigilli e il contesto scalare/lista lo rendono potente per chi lo conosce e ostico per chi deve mantenerne il codice.
Oggi si legge più di quanto si scriva. Per script nuovi si sceglie Python o Bash, ma Perl resta preinstallato su quasi ogni sistema Unix-like e lo incontrerai mantenendo script esistenti, strumenti di sistema e pipeline di bioinformatica meno recenti.
Per vedere come si colloca rispetto agli altri linguaggi, anche quelli nati per sostituirlo, c'è la panoramica su tutti i linguaggi di programmazione.
Contenuto redatto con l'assistenza di strumenti di intelligenza artificiale e rivisto dalla redazione di Codegrind, che ne è responsabile. Hai trovato un errore? Scrivici.