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 ($@ =~ /Illegal/) { print(“Fatal!… $@”) ; } 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 $@ 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