Como o system() do Perl pode imprimir o comando que está sendo executado?
Pergunta
Em Perl, você pode executar comandos do sistema usando system() ou `` (crases).Você pode até capturar a saída do comando em uma variável.No entanto, isso oculta a execução do programa em segundo plano para que a pessoa que executa o script não possa vê-lo.
Normalmente isso é útil, mas às vezes quero ver o que está acontecendo nos bastidores.Como você faz com que os comandos executados sejam impressos no terminal e a saída desses programas impressa no terminal?Este seria o .bat
equivalente a "@echo ativado".
Solução
Pelo que entendi, system() imprimirá o resultado do comando, mas não o atribuirá.Por exemplo.
[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
Backticks irá capturar a saída do comando e não imprimi-la:
[daniel@tux /]$ perl -e '$ls = `ls`; print "Result: $ls\n"'
Result: bin
boot
dev
etc
home
lib
etc...
Atualizar: Se você quiser imprimir o nome do comando que está sendo system() também, eu acho Rudda abordagem é boa.Repetido aqui para consolidação:
sub execute {
my $cmd = shift;
print "$cmd\n";
system($cmd);
}
my $cmd = $ARGV[0];
execute($cmd);
Outras dicas
Não conheço nenhuma maneira padrão de fazer isso, mas você pode definir uma sub-rotina para fazer isso por você:
sub execute {
my $cmd = shift;
print "$cmd\n";
system($cmd);
}
my $cmd = $ARGV[0];
execute($cmd);
E então veja-o em ação:
pbook:~/foo rudd$ perl foo.pl ls
ls
file1 file2 foo.pl
Em vez disso, use aberto.Então você pode capturar a saída do comando.
open(LS,"|ls");
print LS;
Aqui está uma execução atualizada que imprimirá os resultados e os retornará:
sub execute {
my $cmd = shift;
print "$cmd\n";
my $ret = `$cmd`;
print $ret;
return $ret;
}
Hmm, interessante como pessoas diferentes estão respondendo a isso de maneiras diferentes.Parece-me que mk e Daniel Fone interpretou-o como querendo ver/manipular o stdout do comando (nenhuma de suas soluções captura stderr fwiw).Eu penso Rudd chegou mais perto.Uma reviravolta que você poderia fazer na resposta de Rudd é substituir o comando system() integrado com sua própria versão para que você não precise reescrever o código existente para usar seu comando execute().
usando o sub execute() da postagem de Rudd, você poderia ter algo assim no topo do seu código:
if ($DEBUG) {
*{"CORE::GLOBAL::system"} = \&{"main::execute"};
}
Acho que vai funcionar, mas tenho que admitir que isso é vodu e já faz um tempo que escrevi esse código.Aqui está o código que escrevi anos atrás para interceptar chamadas do sistema em nível local (namespace de chamada) ou global no momento do carregamento do módulo:
# 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"};
}
}
Outra técnica para combinar com as demais citadas nas respostas é utilizar o tee
comando.Por exemplo:
open(F, "ls | tee /dev/tty |");
while (<F>) {
print length($_), "\n";
}
close(F);
Isso imprimirá os arquivos no diretório atual (como consequência de tee /dev/tty
) e também imprima o comprimento de cada nome de arquivo lido.