В Perl вы можете выполнять системные команды, используя system () или `` (backticks). Вы даже можете записать вывод команды в переменную. Однако это скрывает выполнение программы в фоновом режиме, поэтому человек, выполняющий ваш сценарий, не может его увидеть.
Обычно это полезно, но иногда я хочу посмотреть, что происходит за кулисами. Как сделать так, чтобы выполненные команды выводились на терминал, а выходные данные этих программ выводились на терминал? Это будет .bat
эквивалентно "@echo on".
Как я понимаю, 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 (), я думаю, что подход Радда хорош. Повторяется здесь для консолидации:
sub execute {
my $cmd = shift;
print "$cmd\n";
system($cmd);
}
my $cmd = $ARGV[0];
execute($cmd);
Вместо этого используйте open. Затем вы можете захватить вывод команды.
open(LS,"|ls");
print LS;
Я не знаю ни одного способа сделать это по умолчанию, но вы можете определить подпрограмму, чтобы сделать это для вас:
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
Хм, интересно, как разные люди отвечают на это по-разному. Мне кажется, что mk и Daniel Fone интерпретировали это как желание видеть / манипулировать stdout команды (ни одно из их решений не захватывает 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
), а также распечатывать длину каждого прочитанного имени файла.
Вот обновленное выполнение, которое напечатает результаты и вернет их:
sub execute {
my $cmd = shift;
print "$cmd\n";
my $ret = `$cmd`;
print $ret;
return $ret;
}
system
команды состоит в том, что онаsystem
имеет сложный прототип, который не может быть реплицирован системой, заданной пользователем. В результате некоторый код просто не будет работать, если вы замените егоsystem
на свою версию.