PDA

Visualizza la versione completa : Aiuto per script Perl


roberto150
22-10-2007, 17:39
Ciao, sono un neofita di Perl, sto cominciando ad usarlo per la tesi. Devo realizzare uno script che in pratica deve analizzare un file di testo, che non è altro che una sequenza di circa 1000 comandi linux (per esempio: sudo, ls, pwd, cd, ssh, ecc....), uno per ogni riga, le righe sono numerate. Quello che deve fare lo script è contare il numero di volte che è stato usato ogni comando e calcolare le distanze (minima, massima e media) tra un comando e ogni altro comando, per distanza intendo il numero di righe.
Faccio un esempio:

file di testo con i comandi:

7 ls
8 cd
9 sudo
10 ls
11 ls
12 more
13 clear
14 rm
15 ls
16 htmlview
17 htmlview
18 lsof
19 cd
20 ssh
21 sudo

Allora le distanze sono
- ls e cd ---> minima=1 (posizioni 7 e 8),massima=4 (pos. 15 e 19),media=2.5
- ls e sudo --> min=2 (pos 7 e 9), max=6 (pos. 15 e 21), media=4
- ls e ls --> min=1 (pos 10 e 11), max=4 (pos. 11 e 25), media=2.5
- ls e more ....................
ecc..........

non so se avete capito...
avete qualke suggerimento??

MARTEDI
23-10-2007, 08:51
Ma tu vuoi la soluzione o una dritta?
Vabbèh, io comincerei con il trasformare il file in un array:

open (FILE,"nome_file.txt");
@RIGHE=<FILE>;
close (FILE);

poi imposterei delle variabili di partenza per il conteggio e quindi farei un ciclo foreach sull'array:

$quanti_ls=0;
$quanti_more=0;
...
$dist_min_ls_cd=10000; #partendo alti perchè sul confronto si guarda il valore più basso (questa però è assurda, secondo me la minima sarà quasi sempre 1)
...

foreach $RIGHE(@RIGHE)
{
#se nella riga c'è il numero di riga lo scorpori e lo metti in una variabile per calcolare le distanze
chop $RIGHE; #togli il carattere "\n" di ogni riga
@var=split(/ /,$RIGHE);
$numero_tiga=$var[0];
$comando=$var[1];

#qui inserisci le condizioni che ricalcolano le variabili impostate
if ($comando eq "ls")
{$quanti_ls++}
...

}

alla fine stampi i risultati.

Quello che non capisco è come mai all'università vi facciano usare il perl!!?!!!
Pensavo che questo linguaggio fosse al tramonto.
Fra l'altro è impossibile trovare dei libri sul perl!!!

roberto150
23-10-2007, 09:34
il perl all'università nn l'ho studiato, solo che devo usarlo per la tesi, poichè a quanto pare è il linguaggio che più si adatta per analisi di file di testo, grazie alle espressioni regolari...
pensavo appunto che il suggerimento avrebbe compreso l'uso di espressioni regolari...
cmq grazie per la dritta... vedrò di adattare il tuo codice e ti farò sapere...

MARTEDI
23-10-2007, 11:36
con le espressioni regolari mi viene in mente una cosa del genere.
Metto il testo in una variabile
$var="";

open (TXT,"testo.txt");
while (<TXT>)
{
#tolgo gli spazi
$_ =~ s/ //g;
#genero la variabile
$var="$var$_";
}
close (TXT);

#ora $var equivale al tuo testo
#quanti ls ci sono?
$quanti_ls = split(/ls\n/,$var)-1;

per le distanze tra un comando e l'altro la faccenda si fa un po' più lunghetta (da parte mia!) per risponderti in 5min :master: ... Ci sono motli modi per risolvere, magari qui qualcuno ne tira fuori di migliori :D

roberto150
23-10-2007, 19:12
ok l'ho provato e funziona

nn ho capito bene cosa fa il comando split, o meglio ho letto in una guida qual è la sua funzione, ma non capisco come lo hai usato tu...

inoltre volevo kiederti, siccome la lista di comandi diversi è molto lunga, mi conviene scrivere le espressioni regolari a mano una ad una, oppure, cosa che ritengo forse più adatta, fare una procedura che riesca a trovare tutti i comandi differenti nel file e fare tutto in automatico, cioè per ogni tipo di comando tenersi il conteggio delle volte che è stato usato..

ti ringrazio molto per l'aiuto

MARTEDI
24-10-2007, 08:50
split serve per separare e genera un array (lo si usa anche in javascript):

se avessi scritto

@prova = split(/ls\n/,$var);

avrei ottenuto un array contenente gli elementi divisi da "ls\n"
Mettendolo così invece:

$quanti_ls = split(/ls\n/,$var)-1;

la variabile rappresenta il numero degli elementi da cui naturalmente devi togliere l'ultimo poichè non è seguito da un "ls\n"!

Per quanto riguarda il ciclo normalmente io faccio così:
1) genero un array contenente le variabili:
@variabili=("ls","cd", ....);

2) poi faccio un ciclo sull'array:
foreach $variabile(@variabili)
{
#qui scrivo:
$mom="quanti_$variabile"; #serve per definire il nome della variabile in uscita (es. $quanti_ls)
${$mom}= split(/$variabile\n/,$var)-1;
}

3) Così sei a posto.
Attento però, accertati che il tuo compilatore perl non sia vecchissimo perchè altrimenti non considererebbe la forma ${$mom}!

roberto150
24-10-2007, 16:28
mhh... non so se mi conviene fare in questo modo perchè i comandi sono talmente tanti.... e poi vi è la possibilità di avere comandi con parametri (per es. "ssh 192.168.1.5", "more secure", ecc....), quindi sarebbe poco fattibile quello che dici tu.
io avevo pensato ad un Hash che ha come chiavi i comandi (seguiti da eventuali parametri, quindi uno stesso comando ma con parametri diversi ha 2 chiavi distinte) e come valore il numero di volte che compare quel comando. Che ne pensi??
Se per te è una buona idea come faccio ad attuarla??
grazie 1000

MARTEDI
24-10-2007, 19:20
ok. A quel punto farei così:
prima cosa se il comando è seguito da un parametro devi trasformare

${$mom}= split(/$variabile\n/,$var)-1;

in

${$mom}= split(/$variabile /,$var)-1;

poichè \n viene conteggiato solo quando vai a capo.


Per avere il conteggio dei comandi legati ai parametri invece secondo me, ti conviene usare una cosa di questo tipo:

open (TXT,"file.txt");
while (<TXT>)
{
# creo un array momentaneo utilizzando degli elementi divisi da uno spazio
# es. la riga è -> 10 ssh 192.168.1.5 -> l'array sarà @mom=(10,'ssh','192...')
@mom=split(/ /,$_);

#definisco le variabili che contano i comandi
$comando_unico=$mom[1];
$comando_con_parametro="$mom[1]_$mom[2]";

#incremento le variabili
${$comando_unico}++;
${$comando_con_parametro}++;

#aggiungo il nome della variabile in un array solo se è la prima volta che la leggo
if (${$comando_unico}==1) #le volte successive è > di 1
{push (@elenco,$comando_unico)}
if (${$comando_con_parametro}==1)
{push (@elenco,$comando_con_parametro)}

}
close (TXT);

# se i miei conti sono giusti alla fine hai @elenco che è il conteggio delle "comparsate":

foreach $elenco(@elenco)
{
print qq{$elenco è comparsa ${$elenco} volte\n}
}

questo sistema però non ti fa usare le espressioni regolari ...

MARTEDI
24-10-2007, 19:29
forse ti conviene aggiustare una cosa su $mom[2] dell'array visto che contiene caratteri strani e potrebbe non funzionare.

Nell'esempio il parametro era 192.168.1.5, che diventerà il nome di una variabile così:

$ssh_192.168.1.5

sicuramente i puntini ti creeranno dei problemi. Quindi ti conviene piazzare subito dopo @mom=... una piccola espressione regolare del tipo:

$mom[2] =~ s/\./_/g;

e la variabile avrà come nome

$ssh_192_168_1_5

Possono esserci altri caratteri fastidiosi
es. carattere "#"
quindi aggiungi anche
$mom[2] =~ s/\#/_/g;

Larry Wall
26-10-2007, 02:00
curiosità...che studi?

Loading