Как система Perl() может напечатать команду, которую она выполняет?
Вопрос
В 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
) а также выведите длину каждого прочитанного имени файла.