Как Perl system() может распечатать команду, в которой он запущен?

В Perl вы можете выполнять системные команды, используя system() или `` (backticks). Вы можете даже захватить вывод команды в переменную. Однако это скрывает выполнение программы в фоновом режиме, так что человек, выполняющий ваш script, не может его увидеть.

Обычно это полезно, но иногда я хочу посмотреть, что происходит за кулисами. Как вы это делаете, чтобы выполняемые команды были напечатаны на терминале, а выход этих программ был напечатан на терминале? Это будет эквивалент .bat "@echo on".

Ответ 1

Как я понимаю, system() будет печатать результат команды, но не назначать ее. Например.

[[email protected] /]$ 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 захватит вывод команды и не распечатает ее:

[[email protected] /]$ perl -e '$ls = `ls`; print "Result: $ls\n"'
Result: bin
boot
dev
etc
home
lib

и т.д...

Обновление: Если вы хотите также напечатать имя команды system() 'd, я думаю, что Rudd хорошо. Повторите здесь для консолидации:

sub execute {
    my $cmd = shift;
    print "$cmd\n";
    system($cmd);
}

my $cmd = $ARGV[0];
execute($cmd);

Ответ 2

Я не знаю какого-либо стандартного способа сделать это, но вы можете определить подпрограмму, чтобы сделать это для вас:

sub execute {
    my $cmd = shift;
    print "$cmd\n";
    system($cmd);
}

my $cmd = $ARGV[0];
execute($cmd);

И затем посмотрите его в действии:

pbook:~/foo rudd$ perl foo.pl ls
ls
file1   file2   foo.pl

Ответ 3

Вместо этого используйте open. Затем вы можете захватить вывод команды.

open(LS,"|ls");
print LS;

Ответ 4

Здесь обновляется выполнение, которое будет печатать результаты и возвращать их:

sub execute {
  my $cmd = shift;
  print "$cmd\n";
  my $ret = `$cmd`;
  print $ret;
  return $ret;
}

Ответ 5

Хм, интересно, как разные люди отвечают на эти разные способы. Мне кажется, что mk и Daniel Fone интерпретировал его как желающий видеть/манипулировать выводом команды (ни одно из их решений не захватывает stderr fwiw). Я думаю, Rudd приблизился. Один поворот, который вы можете сделать в ответ на Rudd, - это перезаписать встроенную команду system() вашей собственной версией, чтобы вам не пришлось переписывать существующий код, чтобы использовать его команду execute().

используя свой элемент execute() из сообщения Rudd, вы можете иметь что-то вроде этого в верхней части вашего кода:

if ($DEBUG) {
   *{"CORE::GLOBAL::system"} = \&{"main::execute"};
}

Я думаю, что это сработает, но я должен признать, что это вуду, и прошло некоторое время с тех пор, как я написал этот код. Вот код, который я написал много лет назад, чтобы перехватить системные вызовы на локальном (вызывающем пространстве имен) или глобальном уровне при загрузке модуля:

  # 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"};
    }
  }

Ответ 6

Другим методом, который должен сочетаться с другими, упомянутыми в ответах, является использование команды tee. Например:

open(F, "ls | tee /dev/tty |");
while (<F>) {
    print length($_), "\n";
}
close(F);

Это приведет к тому, что вы распечатаете файлы в текущем каталоге (как следствие tee /dev/tty), а также распечатайте длину каждого прочитанного имени файла.