#!/usr/bin/perl
#
# SCRIPT: testo.pl
#
# VERSIONE: 0.4
# DATA: 20/08/2004
#
# AUTORE:
# Vittorio Zuccala' (nathanvi)
# perlmonk@nathanvi.it
#
# LICENZA
# Questo programma è free software; puoi redistribuirlo e/o modificarlo
# nei termini della GNU General Public License come e' stata pubblicata
# dalla Free Software Foundation dalla versione 2 della Licenza.
# Questo programma e' distribuito nella speranza di essere utile,
# ma SENZA ALCUNA GARANZIA; non si fornisce alcuna garanzia di
# COMMERCIALIZZAZIONE o FUNZIONAMENTO. Consulta la
# GNU General Public License per maggiori dettagli.
# Originale: http://www.gnu.org/licenses/gpl.txt
# Italiano: http://www.softwarelibero.it/gnudoc/gpl.it.txt
#
# SISTEMA OPERATIVO:
# Scritto su debian linux con scite
# Provato con successo in ambiente windows
#
# OBIETTIVO:
# Mi e' capitato spesso di dover fare delle azioni ripetitive su file,
# soprattutto di testo e dover scrivere un semplice scriptino per
# automatizzare l'operazione.
# Spesso, pensando che non avrei piu' dovuto fare la medesima cosa l'ho eseguito
# una volta e poi basta.
# Questo script raccoglie alcune piccole utility per manipolare file di testo e non solo.
# Di seguito sono riportate le operazioni che fa:
#
# --commenta--
# Serve per inserire un carattere di commento "#" o diverso se specificato
# davanti ad ogni riga di un file.
# Puo' essere molto utile quando, ad esempio si prende del codice di altri e lo si vuole
# eseguire pezzo per pezzo. In questi casi lo si commenta in toto e poi si tolgono
# i commenti solo davanti i pezzi di codice che si vuole eseguire
#
# --decommenta--
# Fa l'esatto contrario.
# Toglie tutti i commenti davanti alle righe.
# Il carattere di default e' il # ma si puo' modificare con una opzione
# Per questo motivo, se prima si era utilizzata la funzione commenta si consiglia di
# non togliere il doppio '#' davanti ai veri commenti perche' sara' tolto il primo comunque.
#
# --pm2txt--
# Scaricando script dal sito http://www.perlmonks.org, quando le righe sono troppo lunghe,
# va a capo inserendo un + all'inizio della nuova riga
# Questa funzione serve per eliminare questo + e accodare la riga alla precedente
#
# --fix2csv--
# Serve per convertire un file FDF dove ogni campo e' a lunghezza fissa in uno nel quale
# ogni campo e' separato da un separatore chiamato anche CSV.
# Questo puo' essere utile se si hanno software
# aziendali o importazioni (tipicamente da AS/400) in file di tipo fdf ovvero a lunghezza fissa
# e li si vuole importare in programmi come excel, access o, meglio mysql, postgres...
# Il separatore sara' da specificare in linea di comando.
# In questo caso lo script analizza un file "pippo" con campi a lunghezza fissa
# e ne restituisce uno identico con le lettere "bis" davanti del tipo "bis_pippo" con separatore.
#
# --csv2fix--
# Fa l'esatto contrario del precedente.
# In realta' non mi e' mai capitato di utilizzarlo ma mentre ero in ballo ... :-))
#
# --ricerca--
# Cerca ricursivamente una parola o una stringa, specificata da linea di comando
# nei file contenuti in una directory e nelle directory figlie.
#
# --md5--
# Quando ci passiamo dei file con amici o li scarico da internet, capita di avere a
# disposizione la firma MD5. Questa funzioncina non fa altro che controllare che tale
# firma sia corretta e che, quindi, il file in nostro possesso sia proprio quello che
# cerchiamo. In caso contrario ci mostra la firma del file che abbiamo. Per questo motivo
# puo' anche essere utilizzato per generare la firma md5 se non si ha a disposizione
# il comando md5sum (come avviene nei sistemi win32). Per fare cio' basta specificare
# una firma nulla dopo aver specificato il file da controllare.
#
# BACHI:
# Nessun baco riscontrato fino ad ora;
# Si prega contattare l'autore nel caso in cui si scopra qualche baco
#
# DIPENDENZE MODULI:
# Tie::File (Gia' installato di default in ogni distribuzione perl)
# File::Find (Gia' installato di default in ogni distribuzione perl)
# Getopt::Std (Gia' installato di default in ogni distribuzione perl)
# Digest::MD5 (Gia' installato di default in ogni distribuzione perl)
#
# INSTALLAZIONE:
# 1) Cambia la prima riga dello script inserendo il path corretto del tuo
# interprete perl
# Es linux: /usr/bin/perl oppure /bin/perl
# Es windows: c:\perl\bin\perl.exe oppure c:\programmi\perl\bin\perl.exe
#
# 2) Copia lo script in una directory presente nel path
# Es linux in /usr/bin
# Es windows in c:\ o c:\windows
#
# UTILIZZO:
# --commenta-- e --decommenta-- e --pm2txt--
# text.pl -c (de)commenta/pm2txt -f files_da_elaborare
# --fix2csv--
# text.pl -c fix2csv -f nome_file -n numero_campi [-s separatore o #] -l lunghezza_campi_in_ordine
# --csv2fix--
# text.pl -c csv2fix -f nome_file -n numero_campi [-s separatore o #]
# --ricerca--
# text.pl -c ricerca -t testo_da_ricercare
# --md5--
# text.pl -c md5 -f file_da_controllare -m firma_md5
#
#
# ESEMPIO:
# --commenta-- e --decommenta-- e --pm2txt--
# text.pl -c (de)commenta/pm2txt -f "pippo.pl pluto.pl"
# --fix2csv--
# text.pl -c fix2csv -f pippo.txt -n 3 -s ; -l 4 5 6
# --csv2fix--
# text.pl -c csv2fix -f pluto.txt -n 3 -s #
# --ricerca--
# text.pl -c ricerca -t "Andava a casa"
# --md5--
# text.pl -c md5 -f pippo.pl -m firmettina
#
#
# INTERPRETE PERL:
# Se hai scaricato questo programma è molto probabile che tu sappia
# cosa sia perl e, probabilmente, hai già un interprete installato sul tuo sistema.
# Se cosi' non fosse, per far funzionare questo script, hai bisogno di
# un altro programma che interpreti i comandi.
# Puoi trovare l'interprete perl su internet e liberamente scaricabile.
# Linux: Si utlizzi il tool di installazione pacchetti della propria distribuzione
# Debian: apt-get install perl
# Windows: http://www.activestate.com/Products/ActivePerl/
# Altri OS: http://www.perl.com/CPAN/ports/index.html
#
# INSTALLARE I MODULI AGGIUNTIVI
# Alcuni scipt richiedono l'installazione di moduli aggiuntivi
# In tal caso:
# In linux:
# 1) aprire una shell e prendere i privilegi di root
# 2) perl -MCPAN -e shell
# 3) install Nome::Modulo
#
# In windows:
# 1) aprire il prompt dei comandi
# 2) ppm
# 3) install Nome::Modulo
#
# Questo modulo si basa su moduli standard.
# Nessun modulo aggiuntivo e' richiesto.
# Inizializzo i moduli
use strict;
use Tie::File;
use File::Find;
use Getopt::Std;
use Digest::MD5;
# Inizializzo le variabili che servono per le varie funzioni
my @files;
my @argv;
my @dir=('.');
my @estensioni=('.pl','.txt','.php');
my %opt;
#########################################
# Prende le opzioni se ci sono:
# c--> comando
# f--> file da elaborare
# h--> help
# l--> lista lunghezza campi per fix2csv
# m--> firma md5
# n--> numero di campi per il fix2csv
# s--> separatore di campi per il fix2csv
# t--> testo da ricercare ricursivamente
getopt('cfhlmnst',\%opt);
#########################################
#Controlla che ci sia una richiesta di help
#oppure se l'utente non ha inserito nessuna
#opzione specifica.
#In tal caso restituisce un help
info_gen() unless(%opt);
info_part() if($opt{h});
#########################################
# Fornisco all'utente l'elenco delle opzioni
# digitate e si da l'opportunita'
# continuare o di fermarsi.
print "Hai inserito le seguenti opzioni.\n\n";
foreach(sort keys(%opt)){
print "Opzione $_: $opt{$_}\n";
}
print "Premi un tato per continuare o CTRL+C per fermare...\n";
<STDIN>;
####################################
# Se si arriva a questo punto significa che
# l'utente ha inserito delle opzioni che
# lo soddisfano e vuole continuare l'esecuzione
# dello script
if($opt{c} eq "commenta"){
controlla_files();
foreach my $file (@files){
controlla_esistenza_file($file);
commenta($file)
}
}
elsif($opt{c} eq "decommenta"){
controlla_files();
foreach my $file (@files){
controlla_esistenza_file($file);
decommenta($file)
}
}
elsif($opt{c} eq "pm2txt"){
controlla_files();
foreach my $file (@files){
controlla_esistenza_file($file);
pm2txt($file)
}
}
elsif($opt{c} eq "fix2csv"){
controlla_files();
foreach my $file (@files){
controlla_esistenza_file($file);
fix2csv($file)
}
}
elsif($opt{c} eq "csv2fix"){
controlla_files();
foreach my $file (@files){
controlla_esistenza_file($file);
csv2fix($file)
}
}
elsif($opt{c} eq "ricerca"){
ricerca();
}
elsif($opt{c} eq "md5"){
md5();
}
elsif(!$opt{c}){
print "Devi inserire un comando!!\n";
die "'text.pl -h comandi' per una lista\n\n";
}
##########################################################################
##########################################################################
######### FUNZIONI ##########################
##########################################################################
##########################################################################
#####################################
# CONTROLLA FILES
sub controlla_files{
if($opt{f}){
@files=split(/ /,$opt{f});
}
else{
print "Mi dispiace ma questo comando richiede uno o piu' files\n";
print "\tda elaborare. Per fare cio' inerisci l'opzione -f e se\n";
print "\thai la necessita' di piu' files mettili fra apici\n";
print "\tEsempio: text.pl -c comando -f \"pippo pluto paperino\"\n";
die "Rilancia lo script\n";
}
}
#####################################
# CONTROLLA ESISTENZA FILE
sub controlla_esistenza_file{
my $file=shift;
if(-e $file){
print "file $file esiste...\n";
}
else{
die "$file non esiste o non riesco ad aprirlo: $!\n";
}
}
#####################################
# COMMENTA
sub commenta{
my $file=shift;
my @righe;
tie @righe, 'Tie::File', $file or die "Non riesco ad aprire il file: $!\n";
print "Lo sto commentando da cima a fondo :-)\n";
foreach my $riga (@righe){
$riga='#'.$riga;
}
print "Fine commenti...\n\n\n";
untie @righe;
}
#####################################
# DECOMMENTA
sub decommenta{
my $file=shift;
my @righe;
tie @righe, 'Tie::File', $file or die "Non riesco ad aprire il file: $!\n";
print "Lo sto decommentando da cima a fondo :-)\n";
foreach my $riga (@righe){
$riga=~s/^\#(.*)/$1/;
}
print "Ho finito di togliere i commenti...\n\n\n";
}
#####################################
# PM2TXT
sub pm2txt{
my $file=shift;
my @righe;
tie @righe, 'Tie::File', $file or die "Non riesco ad aprire il file: $!\n";
print "Lo sto convertendo da cima a fondo :-)\n";
my $i=0;
my $count=0;
foreach my $riga (@righe){
#Se inizia la riga con un + lo cancello e accodo la riga alla precedente
#eliminando quella corrente.
#Torno in dietro di uno (--$i) per riprendere dalla stesso numero di
#riga dato ce ho eliminato quella che stavo esaminando.
if($righe[$i]=~/^\+.*/){
++$count;
$righe[$i]=~s/^\+(.*)/$1/;
$righe[$i-1]=$righe[$i-1].$righe[$i];
splice(@righe,$i,1);
--$i;
}
++$i;
}
print "Totale righe convertite $count\n";
print "Fine conversione...\n\n\n";
untie @righe;
}
#####################################
# FIX2CSV
sub fix2csv{
my $file=shift;
my @righe;
my $separatore=$opt{s};
my $num_campi=$opt{n};
my @lista_campi=split(/ /,$opt{l});
if($num_campi && $#lista_campi+1==$num_campi){
$separatore='#' unless($separatore);
tie @righe, 'Tie::File', $file or die "Non riesco ad aprire il file: $!\n";
print "Ho aperto il file $file...\n";
open TEMP, ">bis_$file" or die "Non posso aprire il file bis dove riversare i dati: $! !!\n\n";
print "Ho aperto bis_$file dove sto riversando i dati...\n\n";
foreach my $riga (@righe){
my $i=0;
my $tot=0;
while($lista_campi[$i]){
my $valore=substr($riga,$tot,$lista_campi[$i]);
$tot+=$lista_campi[$i];
$valore=~s/^\s+?//;
$valore=~s/\s+?$//;
++$i;
print TEMP $valore,$separatore if($i<$#lista_campi+1);
print TEMP $valore if($i==$#lista_campi+1);
}
print TEMP "\n";
}
untie @righe;
close TEMP;
print "Ho riversato i dati in bis_$file. Ready to go!\n";
}
else{
print "Devi inserire il numero di campi con l'opzione -n\n";
print "Segue la lista delle lunghezze dei campi con l'opzione -l\n";
print "Esempio: -c fix2csv -n 3 -l 3 5 6\n";
die "Rilancia lo script\n";
}
}
#####################################
# CSV2FIX
sub csv2fix{
my $file=shift;
my @righe;
my $separatore=$opt{s};
my $num_campi=$opt{n};
if($num_campi && $separatore){
tie @righe, 'Tie::File', $file or die "Non riesco ad aprire il file: $!\n";
print "Ho aperto il file $file... Controllo la lunghezza dei campi!\n";
#Il primo giro serve per rendersi conto di quanto sono lunghi i campi
#Li memorizzo in un array @max
my @temp;
my @max;
foreach my $riga (@righe){
my @temp=split(/$separatore/,$riga);
my $i=0;
while($temp[$i]){
$max[$i]=length($temp[$i]) if length($temp[$i])>$max[$i];
$i++;
}
}
untie @righe;
tie my @righe, 'Tie::File', $file or die "Non riesco ad aprire il file: $!\n";
open TEMP, ">bis_$file" or die "Non posso aprire il file bis dove riversare i dati: $! !!\n\n";
print "Ho aperto bis_$file dove sto riversando i dati...\n";
#Altro giro per elaborare i campi ma questa con la lunghezza fissa
#nota a priori dal ciclo precedente
foreach my $riga (@righe){
@temp=split(/$separatore/,$riga);
my $i=0;
while($temp[$i]){
printf TEMP ("%-$max[$i]s",$temp[$i]);
++$i;
}
print TEMP "\n";
}
close TEMP;
untie @righe;
print "\nHo riversato i dati in bis_$file. Ready to go!\n";
}
else{
print "ATTENZIONE: Devi inserire il separatore con l'opzione -s\n";
print "Seguito da il numero di campi con l'opzione -n\n";
die "Riavvia lo script\n";
}
}
####################################
############# RICERCA TESTO IN FILE!!
sub ricerca{
my $ricerca=$opt{t};
die "Devi inserire il testo da ricercare con l'opzione -t\n" unless($ricerca);
print "\nSto per ricercare la stringa '$ricerca'\n";
print "nei file con estensione\n";
foreach(@estensioni){print $_," ";}
print "\nPremi enter per confermare oppure premi esci e cambia\n";
print "la variabile \@estensioni nello script!\n";
<STDIN>;
my @file=find(\&wanted, @dir);
print "Fine ricerca\n\n";
sub wanted {
foreach my $estensione (@estensioni){
if(/$estensione/){
open FILE, $_ or print "Non sono riuscito ad aprire $_: $!";
while(my $riga=<FILE>){
if($riga=~/$ricerca/){
print "Ho trovato la stringa cercata:\n";
print "File: $File::Find::name\n";
print "Stringa:\'$riga\'\n\n";
}
}
}
}
}
}
###########################
# MD5 CONTROLLO
sub md5{
die "Devi inserire la firma trovata md5 per il controllo con opzione -m" unless($opt{m});
die "Devi inserire un file da controllare con opzione -f" unless($opt{f});
controlla_esistenza_file($opt{f});
my $file = $opt{f};
open(FILE, $file) or die "Can't open '$file': $!";
binmode(FILE);
my $firma=$opt{m};
#Verifico la firma MD5
my $controllo=Digest::MD5->new->addfile(*FILE)->hexdigest;
#Effettuo il controllo
if($firma eq $controllo){
print "OK! Il file e' quello voluto!!\n";
}
else{
print "ATTENZIONE!! Non e' il file che vuoi.\n";
print "La firma di questo e': $controllo\n";
}
}
########################################
########################################
# INFORMAZIONI SU
# HELP
########################################
########################################
########################################
# Informazioni generali
sub info_gen{
print "Questo programma raccoglie una serie di utility per \n";
print "la manipolazione di file di testo.\n";
print "Per la lista dei comandi: text.pl -h comandi\n";
print "Per info su un comando: text.pl -h nome_comando\n";
die "Ravvia il programma con la giusta opzione";
}
########################################
# Informazioni su un comando
sub info_part{
if($opt{h} eq 'comandi'){
print "Ogni comando si richiama con l'opzione -c\n";
print "I comandi disponibili sono i seguenti:\n";
print "commenta: serve per mettere un simbolo di commento\n";
print "\tdavanti ad ogni riga di un file in modo da poterlo rivederlo da zero\n";
print "decommenta: fa l'esatto contrario. Toglie davanti ad ogni riga\n";
print "\til simbolo di commento.\n";
print "fix2csv: trasforma un file con campi a lunghezza fissa in un CSV\n";
print "csv2fix: trasforma un CSV in un file con campi a lunghezza fissa\n";
print "md5: controlla la firma md5 di un file\n";
print "pm2txt: fissa il bug dell'importazione degli script dal sito di\n";
print "\tperlmonks nei quali rimane un + all'inizio di alcune righe.\n\n";
die "Per avere info maggiori su un comando: text.pl -h comando\n";
}
elsif($opt{h} eq 'commenta'){
print "Questa feature e' utile a chi programma e, di tanto in tanto \n";
print "scarica degli script da internet che vuole riadattare ai propri\n";
print "scopi. In questi casi puo' essere utile commentare tutto il file\n";
print "in modo da andare a decommentare solo quello che si vuole ed\n";
print "analizzare il comportamento del programma con calma.\n";
print "Utilizzo:\n";
print "text.pl -c commenta -f file_da_commentare\n\n";
die "Riavvia lo script con questa opzione se e' cio' che cercavi\n";
}
elsif($opt{h} eq 'decommenta'){
print "Questa feature e' utile a chi programma e, di tanto in tanto \n";
print "scarica degli script da internet che vuole riadattare ai propri\n";
print "scopi. In questi casi puo' essere utile commentare tutto il file\n";
print "in modo da andare a decommentare solo quello che si vuole ed\n";
print "analizzare il comportamento del programma con calma.\n";
print "Utilizzo:\n";
print "text.pl -c decommenta -f file_da_commentare\n\n";
die "Riavvia lo script con questa opzione se e' cio' che cercavi";
}
elsif($opt{h} eq 'fix2csv'){
print "Questa feature e' utile per coloro che hanno necessita' di \n";
print "importare/esportare spesso dei dati da/a programmi gestionali.\n";
print "Alcuni programmi gestiscono file a lunghezza fissa mentre altri\n";
print "con camppi delimitati da un separatore\n";
print "Lo script converte da file a lunghezza fissa a csv.\n";
print "Utilizzo:\n";
print "text.pl -c fix2csv -f file [-s separatore o #] -n num_campi -l lunghezze_campi\n";
print "text.pl -c fix2csv -f file -s ; -n 3 -l 8 14 9\n\n";
die "Riavvia lo script con questa opzione se e' cio' che cercavi\n";
}
elsif($opt{h} eq 'csv2fix'){
print "Questa feature e' utile per coloro che hanno necessita' di \n";
print "importare/esportare spesso dei dati da/a programmi gestionali.\n";
print "Alcuni programmi gestiscono file a lunghezza fissa mentre altri\n";
print "con camppi delimitati da un separatore\n";
print "Lo script converte da csv a file a lunghezza fissa.\n";
print "Utilizzo:\n";
print "text.pl -c csv2fix -f file -n num_campi [-s separatore o #]\n";
print "text.pl -c csv2fix -f file -n 3 -s #\n\n";
die "Riavvia lo script con questa opzione se e' cio' che cercavi\n";
}
elsif($opt{h} eq 'ricerca'){
print "Questa feature e' utile a chi vuole ricercare\n";
print "del testo su piu' files ricorsivamente e scoprire se ci\n";
print "file che contengono tale testo...\n";
print "Utilizzo:\n";
print "text.pl -c ricerca -t testo_da_cercare\n";
die "Riavvia lo script con questa opzione se e' cio' che cercavi";
}
elsif($opt{h} eq 'md5'){
print "Questa feature soprattutto quando si scaricano o ci passano\n";
print "tramite internet dei file ed abbiamo la firma md5 per controllare\n";
print "che il file sia quello in nostro possesso\n";
print "Utilizzo:\n";
print "text.pl -c md5 -f file_da_controllare -m firma_md5_del_file\n";
die "Riavvia lo script con questa opzione se e' cio' che cercavi";
}
else{
print "Il comando da te inserito non mi e' noto\n";
die "Per una lista di comandi: \"text.pl -h comandi\"\n";
}
}