Как система Perl() может напечатать команду, которую она выполняет?

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

  •  08-06-2019
  •  | 
  •  

Вопрос

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

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

Это было полезно?

Решение

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

[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

Обратные метки будут фиксировать выходные данные команды, а не печатать их:

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

и т.д...

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

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

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

Другие советы

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

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

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

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

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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top