Como o system() do Perl pode imprimir o comando que está sendo executado?

StackOverflow https://stackoverflow.com/questions/17225

  •  08-06-2019
  •  | 
  •  

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".

Foi útil?

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top