Introduzione agli
scripting languages
ed ai WEB tools
Dario Menasce
1
Introduzione
•
•
•
•
•
•
•
•
•
Cosa sono gli scripting languages
Perche’ ci interessa PERL in particolare rispetto ad altri linguaggi di scripting
Guida di sopravvivenza minimale
Breve introduzione alla sintassi
Sviluppo di un semplice esempio come programma stand-alone
Breve introduzione al protocollo HTML e CGI
Interfacciamento del programma di esempio ad un WEB browser
Suggerimenti per reperire documentazione in rete
Conclusioni
2
Cos’e’ uno scripting language?
Scripting language ---> collante tra le funzionalita’ di un sistema operativo
o, piu’ in generale, tra le funzioni primitive di un ambiente applicativo.
3
Es: shell script
kumac
Tcl/Tk
JavaScript
.......
Gli shell script sono legati non solo al soggiacente sistema operativo (UNIX, Win98…)
ma addirittura alla particolare shell in uso (sh, bash, tcsh, …) (problemi di portabilita’)
D’altra parte uno shell script per girare necessita di minime risorse di sistema.
Questo e’ molto importante per un sistemista, in quanto una macchina in grado di
funzionare in modo minimale e’ sicuramente dotata almeno di una shell (generalmente
la shell sh), per cui gli script di quella shell potranno, in linea di principio, funzionare
anche in assenza di ulteriori risorse, quali un interpreter PERL.
Kumac e’ lo scripting language nativo di PAW: abbastanza sofisticato ma non dotato
di capacita’ di interazione col sistema operativo. Vedremo come e’ possibile usare
PERL (con grande vantaggio e soddisfazione) per fargli generare degli script
kumac (un modo di usare PERL come meta-linguaggio)
4
Es: shell script
kumac
Tcl/Tk
JavaScript
.......
Tcl/Tk e’ una coppia di linguaggi adatti alla creazione di interfacce grafiche.
Tcl e’ sofisticato, ma dotato di strutture di dati non sufficientemente articolate.
Esiste un modulo di PERL, chiamato PERL/Tk, che sostituisce Tcl nella coppia di
linguaggi: e’ possibile con esso scrivere sofisticate interfacce utente, come ad
esempio un completo browser o un’interfaccia ad un DAQ.
JavaScript e’ uno scripting language che opera ESCLUSIVAMENTE all’interno di
un WEB browser (tipicamente Netscape o InternetExplorer). E’ utilizzato per
aggiungere funzionalita’ dinamiche alle pagine WEB, come ad esempio verificare la
validita’ dei campi di input di un form prima che questo venga spedito al server.
Questo risparmia al server di verificare la validita’ dei dati in arrivo da centinaia
di clients, demandando ad essi tutta la computazionalita’ necessaria.
5
Es: shell script
kumac
Tcl/Tk
JavaScript
.......
Tutti gli esempi indicati sono legati all’ambiente particolare per i quali erano stati
progettati:
PERL, al contrario, e’ quasi totalmente portabile e general-purpose.
• E’ universalmente disponibile in rete ed e’ gratuito.
• E’ aperto (esistono i sorgenti)
• E’ supportato e sviluppato da una vastissima comunita’
• Esistono ricche librerie di moduli liberamente disponibili in rete come
pure vastissima e’ la documentazione disponibile
6
Kumac: scripting language di PAW (Physics Analysis Workstation)
unix> paw
Limiti
PAW> fun1 1 sin(x)/x 100 -20 20
Identifier (Id)
Numero di punti (bins)
7
Kumac: scripting language di PAW (Physics Analysis Workstation)
unix> paw
PAW> fun1 1 sin(x)/x 100 -20 20
PAW> fun2 2 sin(x)/x*sin(y)/y 100 -10 10 100 -10 10
8
Kumac: scripting language di PAW (Physics Analysis Workstation)
Dopo aver definito gli istogrammi
salviamoli su disco in un file:
unix> paw
PAW> fun1 1 sin(x)/x 100 -20 20
PAW> fun2 2 sin(x)/x*sin(y)/y 100 -10 10 100 -10 10
PAW> his/file 10 histograms_file.his 1024 N
PAW> hrout 0
PAW> close 10
PAW> exit
unix>
Unita’ di I/O
Nome file
Record size
Flag: New file
Salva tutti (0) gli istogrammi definiti
9
Kumac: scripting language di PAW (Physics Analysis Workstation)
unix> paw
PAW> fun1 1 sin(x)/x 100 -20 20
PAW> fun2 2 sin(x)/x*sin(y)/y 100 -10 10 100 -10 10
PAW> his/file 10 histograms_file.his 1024 N
PAW> hrout 0
PAW> close 10
PAW> exit
unix> ls -la *.his
-rw-r--r--
1
menasce
e831
21451365
Sep
8
19:43 histograms_file.his
Vogliamo ora riaprire questo file e stampare
gli istogrammi in formato grafico
10
unix> paw
PAW> his/file 10 histograms_file.his
PAW> his/lis
===> Directory : //PAWC
1 (1) sin(x)/x
2 (2) sin(x)/x*sin(y)/y
Ripristina in memoria i dati degli istogrammi
leggendoli dal file precedentemente salvato
PAW> zon 2 2
PAW> his/plo 1
PAW> Palette 1
PAW> Set Ncol 50
PAW> his/plo 2 colz
PAW> surf 2
PAW> h/plo 2 surf4
11
Supponiamo ora di avere a disposizione 4 files di istogrammi e di voler sommare gli istogrammi
con Id=15 fra loro, mettendo il risultato nell’istogramma con Id=100. Sara’ utile allo scopo
preparare uno script (somma.kumac) e farlo eseguire in PAW.
Macro somma
MaxHistos = 4
Definisce il numero di files da considerare
Do I = 1, [MaxHistos]
Case [I] in
(1) File =
(2) File =
(3) File =
(4) File =
‘pixelreadout.his’
‘pixelnocharge.his’
‘newpixeldata.his’
‘pixelredesign.his’
EndCase
his/fil 1 [File]
if ([I] .Eq. 1) then
his/copy 15 100
else
his/oper/add 15 100 100
endif
Predispone i cicli per ogni file
A seconda del ciclo corrente, definisce
un diverso nome di file a aprire in lettura
Il primo istogramma viene copiato pari pari
in un nuovo istogramma con Id=100
Ogni nuovo istogramma viene sommato a
quello con Id=100
EndDo
his/plo 100
somma.kumac
Sistema poco pratico, soprattutto se i file
hanno nomi non componibili con un algoritmo
automatico e sono in numero molto elevato.
Vedremo come l’uso di PERL ci faciliti nel
compito di automatizzare la scrittura degli
scripts (useremo PERL come meta-linguaggio)
12
Domanda:
io che sono un fisico e non uno studioso di informatica, quali vantaggi posso
trarre dall’uso di PERL nella mia attivita’ quotidiana?
E perche’ linguaggi come il FORTRAN o gli shell scripting possono non essere
ugualmente adeguati allo scopo?
Semplice da imparare
La curva di apprendimento ha una derivata piccola. Si possono
facilmente riciclare le conoscenze di C e di shell programming
Molto sofisticato e flessibile
Pur essendo semplice da imparare, e’ pur sempre un linguaggio
estremamente ricco di attributi e funzionalita’
Portabile
Questo e’ uno dei maggiori punti di forza di PERL: una volta
scritto il codice, esso funzionera’ senza modifiche sul 99% delle
piattaforme esistenti.
Ottimo collante fra processi
PERL e’ nato per manipolare file e stringhe, ma si e’ evoluto
fino a divenire un ottimo collante fra procedure eterogenee,
poiche’ sa interagire col soggiacente sistema operativo in modo
molto efficace.
E’ estremamente sintetico
La sua sintassi e’ molto concisa: cio’ permette di descrivere in
poche istruzioni algoritmi piuttosto complessi.
Cio’ potenzialmente minimizza la possibilita’ di introdurre errori
involontari nel codice
13
E’ interpretato
Pur essendo interpretato e’ piuttosto veloce in
esecuzione. Inoltre ha la caratteristica di avere
accesso a run-time al proprio compilatore
La sua velocita’ non e’ pero’ comparabile a quella di un
programma compilato (inadatto ad applicazioni che siano
critiche nei tempi di esecuzione, tipo DAQ o real-time)
Prima di passare ad una descrizione del linguaggio PERL, vediamo se il
nostro computer ha una versione installata e recente dell’interpreter.
14
> which perl
Fornisce il full path-name dell’eseguibile purche’ sia
in uno di quelli specificati nella variabile PATH
> whereis perl
Cerca l’eseguibile, e le eventuali man-pages associate
in tutto il tree / (root directory tree)
> locate perl
Cerca in un apposito database del sistema (solo su LINUX)
tutte le istanze di files contenenti la stringa perl interpretata
come regular-expression
Versione 5.004_01
> perl -v
This is perl, version 5.004_01
Copyright 1987-1997, Larry Wall
Perl may be copied only under the terms of either the Artistic
Licence or the GNU General Public Licence, which may be found in
the PERL 5.0 source kit.
> perl -w source.pl
Interpreta il file source.pl, stampa eventuali warnings di
compilazione, e lo esegue
> perl -c source.pl
Interpreta il file source.pl, stampa eventuali warnings di
compilazione, ma NON lo esegue
15
La sintassi di PERL
I tipi di variabili
Gli scalari
$Number
= 16;
$mass
= 1.868 ;
$myName
= “Dario Menasce” ;
Come in C, anche in PERL un’istruzione e’ terminata dal ;
$Address = “Via Celoria” ;
$FullAdd = “$myName $Address $Number.” ;
print(“$FullAdd\n”) ;
> chmod +x test.pl
> perl -w test.pl
test.pl
Dario Menasce, Via Celoria 16.
$myName
$Address
$Number
16
La sintassi di PERL
I tipi di variabili
I vettori
Come in C, i vettori in PERL partono da 0 !!!
@VectorA = (1,2,3,4,5,6) ;
@VectorB = (“Bob”,25,$VectorA[3],(25,26,’String’) ) ;
@VectorC = (@VectorB ,$VectorA[0]) ;
Nome collettivo
Un singolo elemento di un vettore
e’ uno scalare!
Il nome collettivo di un vettore e’ identificato dal simbolo @
Vediamo alcune delle operazioni utili sui vettori che e’ possibile
realizzare con una singola istruzione (i fisici amano i vettori…)
17
La sintassi di PERL (I)
@fred = (1, “ab”, $var) ;
Inizializziamo un vettore con tre elementi:
@barney
= @fred ;
Ne facciamo una copia
$length
= @fred ;
Calcoliamo il numero di elementi del vettore $length varra’ 3
($one)
= @fred ;
Estraiamo il primo elemento del vettore
(equivalente a $one = $fred[0] ossia 1)
($a,$b,$c) = @fred ;
Estraiamo i singoli elementi del vettore
$a = 1, $b = “ab” e $c = $var
($b,$a)
= ($a,$b) ;
Scambiamo $a con $b
$fred[1]
= “alpha” ;
Riassegna un valore al secondo elemento del vettore
$new
= $fred[0]++;
Incrementa il primo elemento del vettore (diventa 2)
$new
= $fred[1]++ ;
Incrementa il secondo elemento del vettore: poiche’
e’ una stringa, incrementa il valore ASCII dell’ultimo
carattere della stringa (diventa ac)
@fred[1,2] = @fred[2,1];
Scambia fra loro il secondo e terzo elemento del
vettore (operando su slices del vettore)
$fred[2]
Restituisce l’indice dell’ ultimo elemento del vettore
18
(in questo caso 2)
+= 4 ;
La sintassi di PERL (II)
@fred = (1, “ab”, $var) ;
Inizializziamo un vettore con tre elementi:
$last
= $fred[-1] ;
Restituisce l’ultimo elemento del vettore ($var)
$lastind
= @#fred ;
Restituisce l’indice dell’ ultimo elemento del vettore
(in questo caso 2)
$fred[8]
= “$pippo” ;
Aumenta la dimensione del vettore a 9 elementi
definendo l’ultimo: gli elementi [4],[5],[6],[7]
avranno valore undef
$fred[1]
.= “cd” ;
Concatena al secondo elemento del vettore la stringa
“cd” (si ottiene “abcd”)
19
La sintassi di PERL
Sono possibili manipolazioni arbitrariamente complesse sugli elementi
di un vettore (il confronto con il FORTRAN diverra’ evidente)
@fred = (“sette”, “otto”, “nove”) ;
Inizializzo un vettore a tre elementi contenenti
ognuno una stringa di caratteri
Vediamo come fare per invertire l’ordine degli elementi di questo vettore:
@ord
= (2, 1, 0 ) ;
@back = @fred( @ord ) ;
@back = @fred(2, 1, 0) ;
Inizializzo un secondo vettore a tre elementi contenente
tre numeri che rappresentano l’ordine con cui voglio
riassemblare il primo vettore
Cio’ e’ equivalente a:
Che e’ a sua volta equivalente a:
@back = ($fred[2], $fred[1], $fred[0]) ;
@back = (“nove”, “otto”, “sette”) ;
20
La sintassi di PERL
Gli operatori di stacking:
push, pop, shift and unshift
@mylist = (1, “two”, “three”) ;
$newvalue = 4 ;
push @mylist, $newvalue ;
print( “mylist = @mylist\n” ) ;
mylist = 1 two three 4
Ai vettori e’ associato un ricco assortimento di
operatori capaci di agire su di essi in modo
sintetico. Vediamone alcuni:
Stack
push estende la dimensione del vettore
e aggiunge l’ultimo elemento in coda
$mylist[0]
1
$mylist[1]
two
$mylist[2]
three
$mylist[3]
4
21
La sintassi di PERL
Gli operatori di stacking:
push, pop, shift and unshift
$lastadded = pop( @mylist ) ;
print( “Last added = $lastadded\n” ) ;
Last added = 4
pop rimuove l’ultimo elemento dello stack
(la gestione degli indici e’ a carico di pop)
$mylist[0]
1
$mylist[1]
two
$mylist[2]
three
$mylist[3]
4
22
La sintassi di PERL
Gli operatori di stacking:
push, pop, shift and unshift
$mylist = (1,”two”,”three”) ;
unshift( @mylist, “zero” ) ;
print( “mylist = @mylist\n” ) ;
mylist = zero 1 two three
unshift agginunge un elemento al primo
posto nel vettore: poiche’ rinumera gli
elementi, puo’ essere inefficiente per
vettori molto grandi.
$mylist[0]
zero
$mylist[0]
$mylist[1]
1
$mylist[1]
$mylist[2]
two
$mylist[2]
$mylist[3]
three
23
La sintassi di PERL
Gli operatori di stacking:
$out
push, pop, shift and unshift
= shift( @mylist) ;
print( “Taken out = $out\n” ) ;
Taken out = zero
shift rimuove il primo elemento dello
stack: di nuovo, viene rinumerato tutto il
vettore.
$mylist[0]
zero
$mylist[0]
$mylist[1]
1
$mylist[1]
$mylist[2]
two
$mylist[2]
$mylist[3]
three
24
La sintassi di PERL
Gli operatori di ordinamento e sorting:
@dritto = (1, 2, 3, 4) ;
@rovescio = reverse( @dritto ) ;
print(“@rovescio\n”) ;
4 3 2 1
@sparso = (“gamma”, “beta”, “alfa” ) ;
@ordinato = sort (@sparso) ;
print(“@ordinato\n”) ;
Come faccio a riempire un vettore digitando
gli elementi dalla tastiera del terminale?
alfa beta gamma
@list = <STDIN> ;
Un programma fatto da questa sola istruzione
riempie ogni elemento del vettore list con una
riga digitata in input. Il procedimento termina
quando viene digitato un EOF (^D)
25
La sintassi di PERL
I tipi di variabili
Le hash tables
Una hash table e’ una collezione di scalari
raggruppata sotto un unico nome, la cui
posizione e’ identificata, invece che da un
numero intero positivo, come accade nel
caso dei vettori, da una
arbitraria stringa di caratteri.
$sede{“Dario Menasce”} = “Milano” ;
$sede{“$utente”}
= “Torino” ;
Chiave
Questa sintassi e’ equivalente a:
Valore
%sede{
“Dario Menasce” => “Milano” ,
“$utente”
=> “Torino”
} ;
Chiave
Ed e’ anche equivalente a:
Valore
%sede = (“Dario Menasce”, “Milano”, $utente, “Torino” } ;
Chiave
Valore
Chiave
Valore
@lista = %sede ;
Una hash puo’ essere trasformata in una lista...
%nuovasede = @lista ;
… e viceversa
26
La sintassi di PERL
I tipi di variabili
Le hash tables
Le hash sono le strutture dati native di PERL dotate della maggior versatilita’
per la costruzione di strutture piu’ complesse, come hash di hash ecc…
$FirstName = “Dario” ;
$LastName = “Menasce” ;
$City
= “Milano” ;
$Employee = “$FirstName $LastName” ;
$Street{“Dario Menasce”
= “Via Celoria 16” ;
$Street{“Daniele Pedrini” = “Piazza Duomo 2” ;
$Address{“$FirstName-$LastName” } = “$Street{$Employee}” . “$City ” ;
print(“Address of $FirstName-$LastName: $Address{$FirstName-$LastName} \n” ) ;
Address of Dario Menasce: via Celoria 16 Milano
27
La sintassi di PERL
I tipi di variabili
$Hash{“alpha”}
$Hash{“beta”}
$Hash{“rho”}
$Hash{“pi”}
Gli operatori sulle hash tables
=
=
=
=
“a”
“b”
“r”
“p”
;
;
;
;
L’operatore each
L’operatore each restituisce, in un contesto
vettoriale, tutte le coppie chiave/valore
definite per la hash in questione
while (($greek,$latin) = each(%Hash)) {
print (“ La lettera greca $greek corrisponde alla latina $latin \n”) ;
}
La
La
La
La
lettera
lettera
lettera
lettera
greca
greca
greca
greca
pi corrisponde alla latina p
rho corrisponde alla latina r
beta corrisponde alla latina b
alpha corrisponde alla latina a
28
La sintassi di PERL
I tipi di variabili
$Hash{“alpha”}
$Hash{“beta”}
$Hash{“rho”}
$Hash{“pi”}
Gli operatori sulle hash tables
=
=
=
=
“a”
“b”
“r”
“p”
L’operatore keys
;
;
;
;
@List = keys ( %Hash ) ;
print (“@List\n”) ;
L’ordine non e’ quello di inserimento, bensi’
pi rho beta alpha
quello determinato dall’algoritmo di hashing.
Se vogliamo una lista ordinata
@List = sort keys ( %Hash ) ; alfabeticamente useremo l’operatore sort
print (“@List\n”) ;
alpha beta pi rho
L’operatore values agisce sui valori
della hash in modo analogo:
@List = sort values ( %Hash ) ;
print (“@List\n”) ;
a b p r
29
La sintassi di PERL
I tipi di variabili
Gli operatori sulle hash tables
$record{“Fred”}
= 205 ;
$record{“Barney”} = 195 ;
$record{“Wilma”} = 30 ;
Esistono innumerevoli modi per
assegnare elementi ad una hash
Ad ogni personaggio associamo il suo
record personale a bowling...
Queste due forme di assegnazione
sono completamente equivalenti
@record{“Fred”, “Barney”, “Wilma”} = (205, 195, 30) ;
Un altro modo ancora...
@Vincitori = {“Fred”, “Barney”, “Dino”} ;
@Valori
= (205, 195, 30) ;
Indipendentemente da come @record
@record( @Vincitori ) = @Valori ;
viene assegnato...
while (($persona, $valore) = each %record) {
print(“Il record di $persona e’ $valore\n” ) ;
}
Il record di Barney e’ 195
Il record di Fred e’ 205
Il record di Wilma e’ 30
30
La sintassi di PERL
Le strutture di controllo
Analoghe a quelle di molti linguaggi (tipo C)
Qualsiasi espressione che, una volta valutata, dia un valore diverso da zero
if (condition1) {
while (condition) {
block1 ;
} elsif (condition2) {
until (condition) {
block ;
block ;
}
}
do {
do {
block2 ;
} else {
block ;
block3 ;
} while (condition);
}
block ;
} until (condition);
In questo caso, prima viene eseguito il blocco di istruzioni block, poi viene valutata la condizione
condition per eventualmente reiterare il blocco
unless (condition) {
for(init;test;incr){
block ;
}
foreach $i (@list) {
block ;
}
block ;
}
31
La sintassi di PERL
Operazioni di I/O
Il concetto di file-handle
open (IN, “myfile.dat”) ;
Un filehandle e’ il nome dato ad una connessione fra
il corrente processo di PERL ed il mondo esterno: e’
quindi un canale di I/O con il soggiacente sistema
operativo, analogo alla UNIT del FORTRAN
while ( $_= <IN>) {
print (“$_\n”) ;
}
close(IN) ;
Questo script si comporta in modo
identico al comando UNIX
cat myfile.dat
La sintassi estremamente concisa di PERL
permette di omettere in molti casi il nome
di una variabile specifica:
il $_ e’ una variabile implicita di PERL
32
La sintassi di PERL
Operazioni di I/O
Il concetto di file-handle (cont..)
open ( LOG, “ > myfile.dat” ) || die “Cannot open file myfile.dat” ;
print
LOG (“Process $proc has completed \n” );
close( LOG ) ;
Ridirige ogni output a LOG verso il file myfile.dat,
analogamente a quanto avviene in UNIX con > o >>
Esiste una ricca serie di qualificatori
capaci di restituire informazioni circa
un file; il loro uso e’ molto semplice:
Se la condizione alla destra del
simbolo di or, ||, e’ falsa, ossia
se il file non puo’ essere aperto,
il programma muore producendo
la frase indicata a destra
$file = “myfile.dat” ;
if (-e “$file”) {
print(“File $file alredy exists!\n”) ;
}
33
La sintassi di PERL
Operazioni di I/O
Il concetto di file-globbing
Come faccio a mettere in un vettore la lista
dei files di una directory che iniziano con la
stringa host seguito da qualsiasi carattere?
@list = < /etc/host* > ;
foreach $file (@list) {
print (“$file”) ;
}
In modo ancora piu’ conciso:
Con una sola istruzione otteniamo i seguenti risultati:
•
•
•
con gli operatori < e > abbiamo aperto un canale di I/O
con la wild-card * specifichiamo un intero range di nomi
l’output dell’operatore < > consiste in una lista di oggetti
e viene quindi valutato in un contesto vettoriale: di
conseguenza ogni oggetto viene inserito in un elemento
del vettore list
foreach (</etc/host*>) {
print ;
}
34
La sintassi di PERL
Operatori di interazione col filesystem locale
Un altro punto di forza di PERL e’ la sua portabilita’ : questa e’ realizzata
creando un’abstraction layer tra la funzionalita’ e l’ implementazione di un
comando diretto al sistema operativo. Vediamo alcuni esempi utili:
unlink (“myfile.dat”) ;
Equivale a...
rm myfile.dat
rename (“myfile.dat myfile.old”) ;
mv myfile.dat myfile.old
link (“fred barney”) ;
ln fred barney
symlink (“fred barney”) ;
ln -s fred barney
mkdir (“newdir”, 0755) ;
mkdir newdir;
chmod 755 newdir
Ecc… ecc...
35
Controllo di processi
E’ frequente la necessita’ di interagire con il sistema operativo dall’interno di un processo,
sia per ricevere informazioni che per far partire e gestire processi esterni. Vediamo
quali strumenti offre PERL per risolvere questo problema assieme a qualche utile esempio.
In quasi tutti i linguaggi di programmazione e’ possibile fornire dei
comandi al soggiacente sistema operativo: cio’ e’ utile per diversi motivi:
Quando occorre eseguire un’operazione per la quale esiste un opportuno comando di sistema che non si
vuole reinventare, come ad esempio il comando di stampa di un file, lpr, o il comando di cancellazione file
36
Controllo di processi
Il metodo piu’ semplice e’ l’uso della funzione system:
system(“ ls comando
-la *.txt “) ;
comando al sistema operativo
L’eventuale output prodotto dal comando viene passato allo
STANDARD OUTPUTdel processo padre (PERL), assieme
allo STANDARD ERROR (si dice che il figlio eredita STDIN,
STDOUT e STDERR dal processo padre)
system(“montecarlo.exe &”) ;
In seguito all chiamata a system, PERL procede alla
creazione (forking) di un sottoprocesso, detto
processo figlio (child process), nell’ambito del quale
viene eseguito il comando specificato (il comando
viene passato alla shell sh).
In questo caso viene fatto partire il processo
montecarlo.exe ma non si aspetta che esso abbia
termine per far tornare il controllo al processo
padre. L’uso e’ problematico nel caso il figlio
generi dell’output , poiche’ questo verra’ mescolato
in modo asincrono con quello del padre.
PERL mi fornisce anche lo strumento per avere
accesso alle variabili ambientali del sistema operativo:
foreach $key (sort keys %ENV) {
print(“$key=$ENV{$key}\n”) ;
}
Queste istruzioni sono assolutamente
equivalenti al comando printenv
System e’ utile, ma l’output generato dal comando eseguito dal sistema
operativo, una volta mandato allo STDOUT, e’ perso, non possiamo usarlo
all’interno dello script PERL che lo ha lanciato!!!.
37
Controllo di processi
L’operatore backticks (`): un primo modo per catturare l’output di un processo di sistema
$now = “Current date is “ . ` date` ;
print(“$now\n”) ;
Current date is Fri Nov
6 15:00:12 MET 1998
Backticks...
Dalla shell, il comando date
produce il seguente output:
Fri Nov 6 15:00:12 MET 1998
In questo caso, date produce una sola linea di output, e quindi i backticks vengono
valutati in un contesto scalare ed il risultato posto in una variabile scalare.
@ListOfConnectedPeople = `who` ;
Il comando who genera un output con diverse linee, una per ogni utente: l’output viene
quindi valutato in un contesto vettoriale, ed ogni linea verra’ memorizzata in un elemento
del vettore @ListOfConnectedPeople
38
Controllo di processi
Un modo ancora piu’ flessibile e’ dato dall’operatore open associato ad una pipe
open( CHI
, “who | “) ;
open( OUT, “ | lpr -Pps_hplit3” ) ;
while (<CHI>) {
print OUT ;
}
close(CHI) ;
Apriamo un altro canale di I/O sul quale
manderemo il comando di stampa...
Occorre terminare il comando
con il simbolo di pipe !!!
Il nome di un file-handle: esso conterra’ il canale di I/O associato
all’output prodotto dal comando who. Occorre specificare che who
deve ridirigere l’output ad una pipe, ossia allo script corrente, ossia...
E se volessimo mandare l’output,
eventualmente modificato,
direttamente ad una stampante
laser?
Facile...
Qui’ c’e’ un semplice print: in realta’
possiamo manipolare ogni riga di output
di who agendo sulla variabile $_ .
Il comando di print OUT spedisce cio’
che who ha prodotto alla pipe OUT, ossia
al comando lpr e quindi alla stampante!!
Per mandare degli argomenti ad una pipe, occorre far
precedere il comando per il sistema operativo dal
simbolo di pipe!!!
39
La capacita’ di PERL di interagire con il sistema operativo, nel modo visto
dagli esempi precedenti e’ uno dei motivi che hanno reso PERL cosi’ popolare
Consideriamo il seguente esempio: vogliamo scrivere un programma
che accetti in input un’arbitraria serie di istruzioni e le esegua.
Una caratteristica interessante di PERL, e’ la capacita’ di eseguire una
stringa di caratteri, interpretandola come un blocco di istruzioni. La stringa
puo’ essere composta leggendo dati dall’esterno del programma: diviene allora
possibile scrivere oggetti di estrema generalita’ come pocket-calculators e
simili. Cio’ e’ possibile grazie al fatto che il linguaggio PERL ha accesso al
proprio interpreter, al quale puo’ fornire ulteriori parti di programma composte
a run-time, dopo che una prima parte del programma e’ gia’ stata compilata ed
eseguita...
40
Consideriamo il seguente esempio: vogliamo scrivere un programma
che accetti in input un’arbitraria serie di istruzioni e le esegua.
while(1) {
print(“> “) ;
$result = eval <STDIN> ;
print(“$result\n”) ;
}
>
Poiche’ 1 e’ costante,
questo loop e’ infinito:
lo interrompero’ con ^C
La variabile $result
viene infine stampata
sullo STDOUT
Stampa il prompt > sul terminale
Eseguiamo ora il programma
dando il seguente input:
$px=12.34;$py=11.34;$pz=123.12; $M=1.869; $p=sqrt($px**2+$py**2+$pz**2);$E=sqrt($M**2+$p**2);
124.269460290934
>
Cio’ che viene dato in input dal terminale viene
valutato interpretandolo come espressione in
PERL ed il risultato della medesima viene posto
nella variabile $result che puo’ essere stampata
$a=3; $ b=4; $c = sqrt($a**2 + $b**2 ) ;
Torna il prompt: qualunque altro tipo di calcolo
diamo in pasto al programma esso sara’ in grado
di eseguirlo e darci il risultato!!!!
RETURN
5
>
$a=3; $ b=4; $c = sqrt($a**2 + $b**2 ) ; print(“ sqrt($a**2 + $b**2 ) = $c\n” ) ;
sqrt(3**2 + 4**2) = 5
1
La funzione print di PERL restituisce 1, valoreche viene mandato
allo STDOUT subito dopo la stringa che print doveva stampare...
Questo semplicissimo programma non solo funge da pocket-calculator, ma e’ in grado
di eseguire qualsiasi parte di un un programma in PERL che gli venga fornito in input!!!!
41
Un altro importante utilizzo di eval riguarda il cosiddetto
error-trapping (detto anche exception- handling)
$a = 14 ;
print(“Enter denominator: “ ) ;
$b = <STDIN> ;
$r = eval { $c = $a / $b } ;
if ([email protected] =~ /Illegal/) {
print(“Fatal!… [email protected]”) ;
} else {
print(“Result: $r\n”) ;
}
Blocco di istruzioni potenzialmente capaci
di generare un errore
In caso di divisione per zero viene generato un errore:
in quel caso PERL riempie la variabile implicita [email protected] con la
stringa di caratteri che descrive il tipo di errore
generato, in questo caso Illegal division by zero
Enter denominator: 7
Result: 2
Enter denominator: 0
Fatal!… Illegal division by zero at esempio_0_1.pl line 4.
42
Le regular expressions in PERL
Uno dei problemi piu’ difficili e comuni da risolvere nella automazione di procedure complesse e’ quella
del riconoscimento di pattern di caratteri: lo strumento principe per risolvere questa categoria di
problemi e’ l’uso delle regular expression, strumento disponibile in diverse famiglie di linguaggi
Una regular expression non e’ altro che un modo sintetico per descrivere un particolare pattern di caratteri, spesso
mediante l’uso di meta-characters: nel caso di PERL e’ quasi un meta-linguaggio, dotato di proprieta’ complesse.
L’esempio piu’ semplice di regular expression e’ la wild-card (il simbolo *), spesso usato in congiunzione
al comando ls di UNIX: essa rappresenta in modo astratto il concetto “qualunque insieme di caratteri”
Vediamo un esmpio articolato, per risolvere il quale l’uso di una regular expression si dimostri particolarmente efficace
43
> ls -la *three*
-rw-r--r--rwxr-xr-x
-rw-r-----rw-r--r--rw-r--r--rw-r--r--rw-r-----rw-r--r--rwxr-x--x
-rw-r--r--rw-r--r--rw-r--r--rw-r--r--rw-r--r--rw-r--r--rw-r--r--rw-r--r--rw-r--r--rw-r--r--rw-r--r--rw-r--r--rw-r--r--rw-r--r--
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
menasce
menasce
menasce
menasce
menasce
menasce
menasce
menasce
menasce
menasce
menasce
menasce
menasce
menasce
menasce
menasce
menasce
menasce
menasce
menasce
menasce
menasce
menasce
e831
e831
e831
e831
e831
e831
e831
e831
e831
e831
e831
e831
e831
e831
e831
e831
e831
e831
e831
e831
e831
e831
e831
202
524
64010
2485
222
2193
2864
70
2002
742
460
15793
2360
753
3710
257
47331
384
5051
268
268
484
268
Nov
Nov
Nov
Nov
Nov
Nov
Nov
Nov
Sep
Apr
Nov
Nov
Jul
Jul
Jul
Jul
Nov
Jul
Nov
Jul
Jul
Nov
Jul
25
21
9
14
9
19
9
21
15
14
20
21
16
16
16
16
25
10
9
10
10
9
10
1997
1997
1997
1997
1997
1997
1997
1997
1997
1998
1997
1997
1997
1997
1997
1997
1997
1997
1997
1997
1997
1997
1997
drve831_threepi.runsts
mcfocus_threepi.csh
mcfocus_threepi.log
mcfocus_threepi.make
mcfocus_threepi.mcf
mcfocus_threepi.nam
mcfocus_threepi.out_dat
mcfocus_threepi.paw
mcfocus_threepi.run
mcfocus_threepi.sf
new_threepi_mc.txt
new_threepi_PAW_mc.txt
threepi.kumac
threepi_match.kumac
threepi_res.ftn
threepi_res.kumac
ugly_threepi.sf
under_threepi.sf
usrinit_threepi.sf
usrmisc_threepi.sf
usrpack_threepi.sf
usrstop_threepi.sf
usrunpk_threepi.sf
> ls -la *three* | grep -v mc | grep sf
-rw-r--r--rw-r--r--rw-r--r--rw-r--r--rw-r--r--rw-r--r--rw-r--r--rw-r--r--rw-r--r--rw-r--r--rw-r--r--rw-r--r--
1
1
1
1
1
1
1
1
1
1
1
1
menasce
menasce
menasce
menasce
menasce
menasce
menasce
menasce
menasce
menasce
menasce
menasce
e831
e831
e831
e831
e831
e831
e831
e831
e831
e831
e831
e831
202
2360
753
3710
257
47331
384
5051
268
268
484
268
Nov
Jul
Jul
Jul
Jul
Nov
Jul
Nov
Jul
Jul
Nov
Jul
25
16
16
16
16
25
10
9
10
10
9
10
1997
1997
1997
1997
1997
1997
1997
1997
1997
1997
1997
1997
drve831_threepi.runsts
threepi.kumac
threepi_match.kumac
threepi_res.ftn
threepi_res.kumac
ugly_threepi.sf
under_threepi.sf
usrinit_threepi.sf
usrmisc_threepi.sf
usrpack_threepi.sf
usrstop_threepi.sf
usrunpk_threepi.sf
Troppi: vogliamo selezionare solo alcuni
di questi file, usando un criterio di
selezione basato sulla presenza nel nome
di un certo pattern di caratteri:
Iniziamo con l’eliminare dalla
lista quelli che contengono i
caratteri mc
Pero’ non vogliamo questo file...
Vogliamo la lista di questi soli files
(terminano tutti per sf)
Risultato raggiunto, ma in un
modo poco flessibile: vediamo
come si puo’ ottenere lo stesso
risultato utilizzando le regular
expressions in uno script PERL
A questo punto basta chiedere che
compaia la coppia di caratteri sf
44
Le regular expressions in PERL
Vediamo come realizzare questa stessa cosa in PERL utilizzando il meccanismo delle regular expressions
#!/usr/local/bin/perl
open(PIPE, “ls -la”) ;
while(PIPE) {
print ;
}
close(PIPE) ;
Fatto cosi’, il programma stampa la lista
di TUTTI i files della directory corrente!!
45
Le regular expressions in PERL
Vediamo come realizzare questa stessa cosa in PERL utilizzando il meccanismo delle regular expressions
#!/usr/local/bin/perl
open(PIPE, “ls -la”) ;
while(PIPE) {
if (m/sf/) {print} ;
m sta per match
}
close(PIPE) ;
sf e’ una regular expression che sta per:
qualsiasi coppia contigua composta da e
solo da s seguito da f minuscoli
In realta’ a noi interessano solo i files che
terminano con sf:
Aggiungiamo alla regexp sf il metacharacter $
che indica in modo sintetico il concetto di
“la regexp deve terminare con”
46
Le regular expressions in PERL
Vediamo come realizzare questa stessa cosa in PERL utilizzando il meccanismo delle regular expressions
#!/usr/local/bin/perl
open(PIPE, “ls -la”) ;
while(PIPE) {
if (m/sf$/) {print} ;
Se poi non desideriamo nella lista i file che
iniziano con mc modifichiamo ulteriormente la
regexp:
if (m/sf$/ && !m/^mc/) {print} ;
Simbolo di NOT
Caret: significa “inizia per”
}
close(PIPE) ;
Questo semplice esempio chiarisce molto bene il concetto di regular expression:
si tratta di un modo simbolico di rappresentare un pattern di caratteri da utilizzare
come filtro di selezione in una richiesta condizionale
Una regular expression: puo’ essere qualcosa di estremamente complesso e criptico
da interpretare, ma si tratta di uno strumento veramente molto potente.
Supponiamo di voler cercare le parole duplicate in un testo:
47
Le regular expressions in PERL
#!/usr/local/bin/perl
while(<DATA>) {
{
print ;
}
}
__END__
Questo testo contiene un certo certo numero di parole
duplicate. Scopo dello script di cui sopra e’ trovarle
e indicare in quale paragrafo paragrafo esse si trovano
Eseguendo questo programma, il testo indicato verra’ semplicemente stampato sul terminale;
48
Le regular expressions in PERL
#!/usr/local/bin/perl
while(<DATA>) {
Per ogni riga letta, itera sui seguenti elementi della riga:
Considera tutti i word boundaries come punto di inizio dell’iterazione:
\b
Considera tutti caratteri che non siano SPACE come possibile parola...
\w\S+
(
Il tutto finche’ compare uno spazio seguito dagli stessi caratteri appena trovati….
\s+
\1
Quando cio’ avviene, memorizza cio’ che sta fra le parentesi rosse in una variabile interna
) +
di PERL, $1, che conterra’ quindi cio’ che ha soddifatto il criterio di selezione
\b
Il tutto ripetuto ad libitum fino al prossimo spazio bianco
}xig
while ( m{
)
x: usa il set completo di metacharacter. i: la ricerca deve essere case-insensitive.
g: la ricerca non deve arrestarsi al primo pattern trovato per ogni parola analizzata
{
print(“La parola $1 risulta duplicata nel paragrafo $.\n” ) ;
}
}
__END__
Questo testo contiene un certo certo numero di parole
duplicate. Scopo dello script di cui sopra e’ trovarle
e indicare in quale paragrafo paragrafo esse si trovano
49
Le regular expressions in PERL
#!/usr/local/bin/perl
while(<DATA>) {
while ( m{
\b
\w\S+
(
\s+
\1
) +
\b
}xig
La variabile $1 corrisponde a cio’ che e’ stato catturato dalle parentesi tonde
ossia ogni pattern che ripete se stesso dopo uno o piu’ spazi bianchi
)
{
print(“La parola $1 risulta duplicata nel paragrafo $.\n” ) ;
}
}
__END__
Questo testo contiene un certo certo numero di parole
duplicate. Scopo dello script di cui sopra e’ trovarle
e indicare in quale paragrafo paragrafo esse si trovano
50
Questo corso ha uno scopo troppo limitato per poter
dare una scorsa approfondita alle regular expressions.
Ci limiteremo quindi alle seguenti considerazioni:
•
•
•
Le regular expressions costituiscono uno dei punti di forza di PERL
(pur essendo utilizzate in molti linguaggi, come awk, sed, egrep, la
loro implementazione in PERL e’ la piu’ sofisticata).
L’apprendimento della sintassi delle regexp e’ piuttosto arduo.
Cio’ nonostante, il loro uso permette la costruzione di programmi
ed algoritmi estremamente efficienti e compatti: il beneficio che
se ne trae vale sicuramente lo sforzo di imparare a conoscerle.
Esiste un testo appositamente dedicato alle regexp, di cui daremo
la citazione bibliografica al termine del corso
Passiamo ora ad una serie di piccoli esempi pratici che mostrano come
PERL possa essere utilizzato nell’attivita’ di un ricercatore impegnato
in un’attivita’ di analisi dei dati. Prima, pero’, un commento:
51
PERL, come gia’ detto, e’ perfettamente adatto anche per rappresentare e risolvere
problemi di matematica, anzi offre molte interessanti proprieta’: vediamo un esempio.
$x = [
[[ 3,
3, 2,
2, 33 ],
],
[[ 5,
5, 9,
9, 88 ]]
] ;
$y = [
[[ 4,
4,
[[ 2,
2,
[[ 6,
6,
] ;
77
33
11
],
],
],
],
]]
$z = mmult( $x, $y ) ;
PrintMatrix( $z ) ;
Un classico problema di moltiplicazione di matrici:
$x e $y sono in realta’ puntatori a delle strutture
(che non sto a dettagliare) che contengono le matrici
realizzate come vettori di vettori.
Se eseguiamo questo programma otteniamo:
$x * $y = [
[ 34 30 ]
[ 86 70 ]
]
L’implementazione del prodotto e’ codificata
in questa funzione: contrariamente al FORTRAN,
essa e’ in grado di determinare da se’ il rango
delle matrici e dimensionare opportunamente
la matrice risultato (in questo caso $z)
La funzione PrintMatrix non fa altro che stampare
il risultato $z in un formato opprotuno, analogo a
quello con cui sono definiti $x e $y
52
Un modo ancora piu’ elegante e sintetico per fare questo tipo di calcolo, e’ quello di
usare un modulo matematico, detto PDL, disponibile su WEB, che realizza il prodotto
di matrici tramite la funzionalita’ di function-overloading (analoga quella del C++).
use PDL ;
$x = [
[[ 3,
3, 2,
2, 33 ],
],
[[ 5,
5, 9,
9, 88 ]]
] ;
$y = [
[[ 4,
4,
[[ 2,
2,
[[ 6,
6,
] ;
77
33
11
],
],
],
],
]]
$z = $x * $y ;
PrintMatrix( $z ) ;
L’inclusione del mudulo PDF, fa si’ che l’operatore * venga ridefinito in modo da
agire sulle matrici x ed y, realizzando il prodotto righe per colonne.
53
Torniamo ora all’esempio citato all’inizio dello script di PAW che somma istogrammi
provenienti da diversi files, e vediamo come sia possibile far scrivere questo script
da una procedura PERL e quale vantaggio ne otteniamo
Macro somma
MaxHistos = 4
Do I = 1, [MaxHistos]
Case [I] in
(1) File = ‘pixelreadout.his’
(2) File = ‘pixelnocharge.his’
(3) File = ‘newpixeldata.his’
(4) File = ‘pixelredesign.his’
EndCase
If ([I] .Eq. 1) then
His/fil 1 [File]
Else
His/copy 15 100
Endif
His/oper/add 15 100 100
His/plo 100
EndDo
Vi rammento che il problema consiste nell’automatizzare
la scrittura di questo pezzo del codice (in questo esempio)
nel caso in cui la lista dei file con istogrammi da sommare
sia ingente (dell’ordine di centinaia o migliaia di files).
54
#!/usr/local/bin/perl
SetFilterRegexp() ;
GetFilesList() ;
sub SetFilterRegexp {
$Filter = “pixel” ;
}
Definisco una variabile che conterra’
la regexp per selezionare i file voluti
sub GetFilesList {
while( $File = <*.his> ) {
if( $File =~ m/$Filter/i ) {
push @FileList, $File ;
}
}
Ciclo su tutti i file della directory corrente
e quelli che soddisfano il criterio di selezione
espresso dalla regexp $Filter vengono aggiunti
al vettore @FileList
Apro in scrittura il file che conterra’ lo script
$Script = “adder.kumac” ;
open(OUT,”>$Script”) || die “Cannot open file $Script at $!” ;
PrintHeader() ;
sub SpecifyFiles {
sub PrintHeader {
SpecifyFiles() ;
$i = 0;
print OUT <<EOB
Macro adder
Close 0
H/Del 0
foreach $file (sort @FileList) {
$i++ ;
print OUT (“ H/Fil 1 $file\n” ) ;
if( $i == 1 ) {
print OUT (“ H/Copy 15 100\n” ) ;
} else {
print OUT (“ H/Oper/Add 15 100 100\n” ) ;
}
print OUT (“ Close 1\n\n” ) ;
}
Macro adder
Close 0
H/Del 0
EOB
H/Fil 1 pixelreadout.his
H/Copy 15 100
H/Oper/Add 15 100 100
Close 1
H/Fil 1 pixelnocharge.his
H/Copy 15 100
H/Oper/Add 15 100 100
Close 1
...
}
Questo e’ il testo dello script sche abbiamo appena creato
55
Quali vantaggi abbiamo ottenuto nel far scrivere lo script
kumac a PERL invece di crearlo noi a mano con l’editor?
•
Lo script e’ del tutto generale:

al cambiare dei files nella directory, lo script si autoconfigura
opportunamente per tenere conto delle novita’ (file nuovi o file spariti)

per selezionare files basati su un diverso aloritmo di selezione bastera’
cambiare il valore della variabile $Filter o implementare un algoritmo piu’
sofisticato per avere uno script sempre up-to-date
•
Nel caso in cui i files siano diverse centinaia o migliaia risulta in pratica
l’unico modo per creare lo script
•
PERL e’ un linguaggio dotato di maggiore versatilita’ che non kumac, e cio’
e’ il motivo per cui risulta cosi’ efficace nell’agire come meta-linguaggio.
Questa tecnica di generazione automatica di programmi in altri linguaggi e’
molto utile in numerosi altri casi (vedremo come cio’ e’ particolaremte vero
nel caso di pagine HTML generate on demand in tempo reale.).
56
Vediamo ora come si puo’ usare PERL per scrivere un
programma che possa essere attivato da un bottone
situato in una pagina WEB.
Due parole su come funziona il protocollo WWW
57
Questo e’ il server dove girera’
lo script in PERL che ci accingiamo
a scrivere
Comunicano tramite il protocollo TCP/IP (Internet)
httpd (server daemon)
Il server ha attivo un daemon che riceve richieste
dal client (il browser) e risponde fornendo i
documenti richiesti.
Il server agisce tramite una serie di files
di configurazione che descrivono come deve
rispondere a richieste dal mondo esterno
Le richieste possono essere di due tipi:
• fornire un documento (testo,immagine,audio,video…)
• eseguire un programma e spedire l’output di questo
indietro al browser (tramite protocollo CGI)
Questo e’ il vostro browser
58
Vediamo ora come realizzare un pagina WEB che contenga un bottone,
premendo il quale ci venga restituita una lista di files di istogrammi
(realizzati con HBOOK).
I files saranno locati sulla macchina remota alla quale avremo sottomesso
la richiesta.
59
<HTML>
<TITLE> esempio_2_0.html </TITLE>
<BODY BGCOLOR=“OldLace”>
Com’e’ fatta una pagina WEB?
Molto schematicamente...
Un tag HTML e’ una direttiva al browser per comunicargli come
interpretare il testo racchiuso fra direttive. Convenzionalmente
indichero’ le direttive in color magenta
<CENTER>
<FORM
ACTION= “http://sgimida.mi.infn.it /cgi-bin/scripts /histo_server.pl”
METHOD= “Get” >
<INPUT
Nome del nodo remoto
Type=“Submit”
Name=“SubmitButton”
Si tratta di un programma
da eseguire, un CGI !
Nome del programma
FORM specifica l’indirizzo del programma da eseguire sulla macchina
remota e la lista degli strumenti di controllo per fornirgli un input
(bottoni, campi di input ecc…)
Value=“Show list of available histograms” >
INPUT specifica il tipo di strumento di controllo da associare al programma
da eseguire. In questo caso ci sara’ un bottone di attivazione.
</FORM>
</CENTER>
esempio_2_0.html
60
Da un qualsiasi browser selezioniamo ora l’indirizzo del file HTML appena creato:
http://sgimida.mi.infn.it/~cntc/esempio_2_0.html
61
Questo e’ il bottone associato all’attivazione del programma
Prima di procedere a premere questo tasto, diamo un’occhiata al codice
PERL dello script associato a questo bottone dalla direttiva ACTION
62
Con un normale editor, creiamo il file histo_server.pl
Questa direttiva informa il browser che cio’ che gli verra’ trasmesso dal
corrente processo sara’ da interpretare come un testo di tipo HTML
#!/usr/local/bin/perl
print(“Content type: text/html\n\n” ) ;
Importante!!!!
$HisDir = “/vtx/boss/mcarlo/histos” ;
Lo STANDARD OUTPUT del corrente processo viene
print <<EOB ;
ritrasmesso al browser che ne ha richiesto l’esecuzione
<HTML>
<TITLE> List of files in $HisDir </TITLE>
<Center>
List of available histogram files on sgimida.mi.infn.it in $HisDir
</Center>
Cio’ che viene posto tra i simboli EOB verra’
passato verbatim allo STANDARD OUTPUT
<OL>
EOB
@ListOfFiles = <$HisDir/*.his> ;
foreach $File (@ListOfFiles) {
print(“<LI> $File \n” ) ;
Esempio di FILE GLOBBING: l’operatore < > restituisce la
}
lista dei files con suffisso his nella directory $HisDir
(agisce in un contesto vettoriale)
print(“</OL>\n” ) ;
Inizio di una ORDERED LIST
<OL>
• Testo
•. .. .
histo_server.pl
63
E’ giunto il momento di premere questo tasto:
64
L’appetito vien mangiando: a questo punto
vorremmo tanto che ogni elemento di
questa lista fosse un link al contenuto del
file, in modo che selezionando un file ci
venisse mostrata la directory degli istogrammi
ivi contenuti….
Difficile?
65
No, basta una piccola modifica allo
script di prima, in aggiunta ad un nuovo
script che faccia girare PAW per fornire
ls lista richiesta. Vediamo come:
66
#!/usr/local/bin/perl
print(“Content type: text/html\n\n” ) ;
Stesso script di prima...
$HisDir = “/vtx/boss/mcarlo/histos” ;
$Server = “http://sgimida.mi.infn.it/cgi-bin/scripts” ;
print <<EOB ;
<HTML>
<TITLE> List of files in $HisDir </TITLE>
<Center>
List of available histogram files on sgimida.mi.infn.it in $HisDir
</Center>
<OL>
EOB
@ListOfFiles = <$HisDir/*.his> ;
Coppia chiave/valore separati dal segno =
foreach $File (@ListOfFiles) {
$Ref = “<A HREF= $Server/show_histos.pl? File=$File > $File </A>” ;
print(“<LI> $Ref
$
\n” ) ;
}
print(“</OL>\n” ) ;
Indirizzo del nodo su cui sta lo script da eseguire
Infine stampiamo il valore del link cosi’ formato sullo STANDARD OUTPUT
del processo corrente (che ovviamente corriponde alla pagina del browser)
Definizione di hyperlink
Indirizzo dello script da eseguire
Marker di inizio dei parametri da passare allo script come input
histo_server.pl
67 a
Stringa di caratteri che su browser apparira’ in blu e sottolineata
rappresentare il link richiesto (in questo caso l’esecuzione dello script)
Voila’, ogni file e’ in realta’ un link ad
uno script che, facendo girare PAW,
produrra’ la lista degli istogrammi
contenuti nel file medesimo!
Prima pero’ vediamo come e’ fatta
questa pagina HTML, output prodotto
dallo script appena descritto...
68
View

Show
Increase font
Decrease font
Ctrl+]
Ctrl+[
Reload
Ctrl R
Show Images
Refresh
Stop page loading <ESC>
Stop animations
Page source
Page info
Character set
Ctrl U
Ctrl I

69
<HTML>
<TITLE>List of available
histogram files</TITLE>
<Body Bgcolor="OldLace">
<Center>
List of available histogram files on sgimida.mi.infn.it in /vtx/boss/mcarlo/histos
</Center>
<OL>
<LI> <A HREF=..../show_histos.pl?File=/vtx/boss/mcarlo/histos/carrara_3pi.his>/vtx/boss/mcarlo/histos/carrara_3pi.his</A>
<LI> <A HREF=..../show_histos.pl?File=/vtx/boss/mcarlo/histos/carrara_kkp.his>/vtx/boss/mcarlo/histos/carrara_kkp.his</A>
<LI> <A HREF=..../show_histos.pl?File=/vtx/boss/mcarlo/histos/carrara_kpp.his>/vtx/boss/mcarlo/histos/carrara_kpp.his</A>
<LI> <A HREF=..../show_histos.pl?File=/vtx/boss/mcarlo/histos/ccbar_3pi.his>/vtx/boss/mcarlo/histos/ccbar_3pi.his</A>
<LI> <A HREF=..../show_histos.pl?File=/vtx/boss/mcarlo/histos/clseccut_dt.his>/vtx/boss/mcarlo/histos/clseccut_dt.his</A>
<LI> <A HREF=..../show_histos.pl?File=/vtx/boss/mcarlo/histos/clseccut_mc.his>/vtx/boss/mcarlo/histos/clseccut_mc.his</A>
<LI> <A HREF=..../show_histos.pl?File=/vtx/boss/mcarlo/histos/data_3pi.his>/vtx/boss/mcarlo/histos/data_3pi.his</A>
<LI> <A HREF=..../show_histos.pl?File=/vtx/boss/mcarlo/histos/data_3pi_1.his>/vtx/boss/mcarlo/histos/data_3pi_1.his</A>
<LI> <A HREF=..../show_histos.pl?File=/vtx/boss/mcarlo/histos/data_kkp.his>/vtx/boss/mcarlo/histos/data_kkp.his</A>
<LI> <A HREF=..../show_histos.pl?File=/vtx/boss/mcarlo/histos/data_kpp.his>/vtx/boss/mcarlo/histos/data_kpp.his</A>
<LI> <A HREF=..../show_histos.pl?File=/vtx/boss/mcarlo/histos/dt_2k2pi.his>/vtx/boss/mcarlo/histos/dt_2k2pi.his</A>
<LI> <A HREF=..../show_histos.pl?File=/vtx/boss/mcarlo/histos/dt_2k2piws.his>/vtx/boss/mcarlo/histos/dt_2k2piws.his</A>
....................................................
1. /vtx/boss/mcarlo/histos/carrara_3pi.his
70
Ovviamente ora viene la parte un po’
piu’ complessa: dobbiamo infatti scrivere
il programma che fa partire PAW sul
file selezionato...
71
Abbiamo visto che la definizione di un hyperlink e’ fatta nel modo seguente:
$Ref = “<A HREF= $Server/show_histos.pl? File=$File > $File </A>” ;
Si possono passare piu’ coppie, separandole con &
La coppia chiave/valore che segue il ? viene spedita al server, il quale la passa
allo script show_histos.pl tramite una environmental variable, chiamata
QUERY_STRING
File=$File & Parameter=$value & ...
QUERY_STRING
Possiamo a questo punto scrive il programma che, facendo girare PAW sul file
selezionato con un click sullo hyperlink, ci fornisca l’elenco degli istogrammi.
Lo script non dovra’ far altro che leggere la QUERY_STRING (PERL offre delle funzioni
adatte allo scopo) e separare le coppie chiave/valore. Chiave diverra’ il nome di una
variabile il cui contenuto sara’ valore.
72
Sub PrintHeader {
print <<EOB;
#!/usr/local/bin/perl
Content-type: text/html
<HTML>
PrintHeader() ;
<TITLE> Output di PAW </TITLE>
<PRE>
DecodeQueryString() ;
EOB
open (OUT, “>lista2.kumac”) || die “Cannot open kumac file” ; }
print OUT<<EOB ;
Macro lista
H/Del 0
Message Working on file $File
H/Fil 1 $File
H/Lis
Close 1
EOB
Sub DecodeQueryString {
$qs = $ENV{‘QUERY_STRING’} ;
@pairs = split( /&/, $qs ) ;
foreach $key_val (@pairs) {
($key, $value) = split(/=/, $key_val);
. . . .
$$key = $value ;
}
Fornisce la variabile $File
Ecco lo script KUMAC che verra’ eseguito da PAW!!
close(OUT) ;
con il nome selezionato dall’
open (OUT, “>paw2.sh”);
utente con lo hyperlink
La KUMAC e’ pronta: ora bisogna creare uno
print OUT<<EOB ;
shell script che faccia partire PAW dandogli
#!/usr/bin/sh
in pasto la KUMAC da eseguire.
/disk3/products/pawx11 <<+++
0
A questo punto non resta che far eseguire
questo script per avviare PAW.
exec lista2.kumac
+++
EOB
system(“chmod +x paw2.sh” ) ;
Ovviamente vanno prima sistemate le protezioni
per poterlo far eseguire dal WEB server!!!!…
Lo script show_histos.pl e’ pronto per
essere eseguito dal WEB server in seguito
alla richiesta di un utente dal browser!!!
73
… continuazione
Apriamo una PIPE per eseguire
lo script che fa girare PAW
open( PAW, “./paw2.sh |”) ;
while( <PAW> ) {
print ;
}
close (PAW) ;
Mentre lo script paw2.sh viene eseguito, tutto cio’
che esso produce sul suo STDOUT viene catturato
nella variabile $_ e stampato sullo STDOUT del
corrente processo (il nostro browser). Ricordo che
l’output di paw2.sh e’ cio’ che stampa la kumac che
produce la lista degli istogrammi.
show_histos.pl
Stampiamo questo output sullo STDOUT, che,
ricordo, e’ la pagina del browser...
Chiudiamo la PIPE, e voila’, lo script e’ pronto a ricevere
comandi dal browser e a fornire liste di istogrammi
74
Clicchiamo ora su uno dei files...
75
76
Sarebbe a questo punto certamente
possibile rendere cliccabile ogni
singolo istogramma di questa lista,
in modo che venga eseguito un script
che ci restituisca l’istogramma in
questione in formato grafico (GIF)
direttamente sul browser (e magari
provvedesse un link aggiuntivo per
la versione POSTSCRIPT ad alta
risoluzione….
77
Lo script che possa fare cio’ non
e’ molto piu’ complicato di quanto
abbiamo visto finora, ma esula dallo
scopo di questo corso. Cio’ che e’
importante e’ cogliere il fatto che
e’ relativamente semplice creare una
interfaccia WEB a normali programmi
di analisi dati, col beneficio che tutti
i membri di unavasta collaborazione
internazionale hanno rapido accesso
ai dati ed anche ai programmi tramite
un’interfaccia standard quale un
browser
78
L’estrema parsimonia sintattica di PERL puo’ essere utilizzata con
grande vantaggio, purche’ cio’ sia fatto cum grano salis, in quanto
il risultato puo’ essere qualcosa di estremamente incomprensibile e
quindi di difficile manutenzione.
Un paio di esempi tratti dallo Annual Obfuscated PERL Contest :
Molto
belloeesteticamente,
francamente
Calcola
stampa i numerima
primi…
(sic)
non sono riuscito a capire cosa fa...
79
80
Operatori di file-test
-r
-w
-x
-o
-R
-W
-X
-O
-e
-z
-f
-d
-l
-p
-s
-b
-c
-t
-T
-B
-M
-A
-C
File is readable by effective uid.
File is writable by effective uid.
File is executable by effective uid.
File is owned by effective uid.
File is readable by real uid.
File is writable by real uid.
File is executable by real uid.
File is owned by real uid.
File exists
File has zero size (it’s empty)
File is a plain-file
File is a directory
File is a symbolic link
File is a nmed pipe
File is socket
File is a block special file
File is a character special file
Filehandle is opened to a tty
File is a text file
File is a binary file
Age of file (at startup) in days since modification
Age of file (at startup) in days since last access
Age of file (at startup) in days since inode change
Back...
81
#!/usr/local/bin/perl
system(“ls -la *.txt“) ;
test.pl
> chmod +x test.pl
> ./test.pl
-rw-------rwx------rw-------rwx------rw-------rw-------rw-r-----rwx-----drwxr-x---rwx-----drwx------rw-r-----
1
1
1
1
1
1
1
1
2
1
4
1
menasce
menasce
menasce
menasce
menasce
menasce
menasce
menasce
menasce
menasce
menasce
menasce
e831
e831
e831
e831
e831
e831
e831
e831
e831
e831
e831
e831
112
1499
80
1639
8927
8685
11623
1580
8192
1552
8192
27248640
Sep
Nov
Sep
Nov
Sep
Sep
Sep
Nov
Sep
Nov
Sep
Sep
10
13
10
13
11
10
10
13
10
13
11
10
14:39
1996
21:42
1996
13:41
20:27
20:27
1996
18:44
1996
13:41
20:22
CP_violation.txt
banner.txt
example.txt
plots.txt
plots_beauty.txt
plots_charm.txt
psi_cross_section.txt
ratio.txt
rose_scheme.txt
transparencies_bristol.txt
usage.txt
zero_level.txt
Back...
82
Scarica

corso di Introduzione a Perl