Come può il sistema system() di Perl stampare il comando che sta eseguendo?
Domanda
In Perl, potete eseguire comandi di sistema usando system() o `` (backtick).Puoi anche catturare l'output del comando in una variabile.Tuttavia, questo nasconde l'esecuzione del programma in background in modo che la persona che esegue lo script non possa vederla.
Normalmente questo è utile ma a volte voglio vedere cosa succede dietro le quinte.Come si fa in modo che i comandi eseguiti vengano stampati sul terminale e l'output di quei programmi venga stampato sul terminale?Questo sarebbe il .bat
equivalente di "@echo on".
Soluzione
A quanto ho capito, system() stamperà il risultato del comando, ma non lo assegnerà.Per esempio.
[daniel@tux /]$ perl -e '$ls = system("ls"); print "Result: $ls\n"'
bin dev home lost+found misc net proc sbin srv System tools var
boot etc lib media mnt opt root selinux sys tmp usr
Result: 0
I backtick cattureranno l'output del comando e non lo stamperanno:
[daniel@tux /]$ perl -e '$ls = `ls`; print "Result: $ls\n"'
Result: bin
boot
dev
etc
home
lib
eccetera...
Aggiornamento: Se vuoi stampare anche il nome del comando che viene system(), penso Ruddl'approccio è buono.Ripetuto qui per consolidamento:
sub execute {
my $cmd = shift;
print "$cmd\n";
system($cmd);
}
my $cmd = $ARGV[0];
execute($cmd);
Altri suggerimenti
Non conosco alcun modo predefinito per farlo, ma puoi definire una subroutine che lo faccia per te:
sub execute {
my $cmd = shift;
print "$cmd\n";
system($cmd);
}
my $cmd = $ARGV[0];
execute($cmd);
E poi vederlo in azione:
pbook:~/foo rudd$ perl foo.pl ls
ls
file1 file2 foo.pl
Utilizzare invece aperto.Quindi puoi acquisire l'output del comando.
open(LS,"|ls");
print LS;
Ecco un'esecuzione aggiornata che stamperà i risultati e li restituirà:
sub execute {
my $cmd = shift;
print "$cmd\n";
my $ret = `$cmd`;
print $ret;
return $ret;
}
Hmm, interessante come persone diverse rispondano a questi modi diversi.Mi sembra mk E Daniele Fone lo ha interpretato come se volesse vedere/manipolare lo stdout del comando (nessuna delle loro soluzioni cattura stderr fwiw).Penso Rudd si avvicinò.Una svolta che potresti apportare alla risposta di Rudd è sovrascrivere il comando system() integrato con la tua versione in modo da non dover riscrivere il codice esistente per utilizzare il suo comandoexecute().
usando il suo subexecutive() dal post di Rudd, potresti avere qualcosa di simile nella parte superiore del tuo codice:
if ($DEBUG) {
*{"CORE::GLOBAL::system"} = \&{"main::execute"};
}
Penso che funzionerà, ma devo ammettere che si tratta di voodoo ed è passato un po' di tempo dall'ultima volta che ho scritto questo codice.Ecco il codice che ho scritto anni fa per intercettare le chiamate di sistema a livello locale (spazio dei nomi chiamante) o globale al momento del caricamento del modulo:
# importing into either the calling or global namespace _must_ be
# done from import(). Doing it elsewhere will not have desired results.
delete($opts{handle_system});
if ($do_system) {
if ($do_system eq 'local') {
*{"$callpkg\::system"} = \&{"$_package\::system"};
} else {
*{"CORE::GLOBAL::system"} = \&{"$_package\::system"};
}
}
Un'altra tecnica da combinare con le altre menzionate nelle risposte è usare il file tee
comando.Per esempio:
open(F, "ls | tee /dev/tty |");
while (<F>) {
print length($_), "\n";
}
close(F);
Questo stamperà entrambi i file nella directory corrente (come conseguenza di tee /dev/tty
) e stampa anche la lunghezza di ciascun nome file letto.