Могу ли я перехватить вызовы оболочки из Perl?

У меня есть сценарий Perl, который вызывает другие программы, т. е. вызывает system и/или exec и/или open с каналом и/или использует оператор обратной кавычки.

Могу ли я запустить этот сценарий таким образом, чтобы он распечатывал аргументы для каждого из вышеперечисленных, чтобы я мог видеть, к чему он обращается?

Например, такая программа, которую я не могу модифицировать

#!/usr/bin/perl
sub get_arg {return "argument$_[0]";}
system "./foo", get_arg(1), get_arg(2);
print `./foo abc def`;

Вызвал что-то вроде этого

perl --shell-trace-on ./myscript.pl

Что в этом случае выведет

./foo argument1 argument2
./foo abc def

Можно отказаться от обычного вывода myscript.pl или смешать его с этой трассировкой.

Большое спасибо.


person spraff    schedule 02.08.2011    source источник
comment
Итак, вы хотите, чтобы сценарий видел, как выглядит команда после расширения оболочки?   -  person Zaid    schedule 02.08.2011
comment
Я хочу зафиксировать выполнение внешних программ и их аргументы.   -  person spraff    schedule 02.08.2011


Ответы (2)


Это считается продвинутым Perl, но вы можете определять подпрограммы в пространстве имен CORE::GLOBAL во время компиляции и захватывать встроенные функции Perl. Вызов функций в пространстве имен CORE вызывает исходные встроенные функции.

BEGIN {
    # have to use a BEGIN block so these functions are defined before
    # run time
    *CORE::GLOBAL::system = sub {
        print STDERR "about to invoke system @_\n";
        return CORE::system(@_);
    };
    *CORE::GLOBAL::qx = sub {
        print STDERR "about to invoke qx/backticks @_\n";
        return CORE::qx(@_);
    };
    *CORE::GLOBAL::exec = sub { ... };
};
system("sleep 5");
print `ls`;
1;

Чтобы применить эту функцию к произвольному автономному сценарию, вы можете поместить этот код в простой модуль (скажем, ShellTrace.pm), а затем вызвать perl с переключателем -MShellTrace. (HT: Перлман):

package ShellTrace;
BEGIN {
    *CORE::GLOBAL::system = sub { ... };
    *CORE::GLOBAL::qx = sub { ... };
    *CORE::GLOBAL::exec = sub { ... };
    *CORE::GLOBAL::open = sub { ... };
}
1;

$ perl -MShellTrace ./myscript.pl
about to invoke system ./foo argument1 argument2 
about to invoke qx/backticks ./foo abc def
...
person mob    schedule 02.08.2011
comment
Впечатляющий трюк, но требует модификации скрипта. Есть ли способ вызвать сценарий без изменений, но с установленной таким образом средой? - person spraff; 02.08.2011
comment
Да — поместите эти изменения в файл .pm (например, ShellTrace.pm, и вызовите свой скрипт с помощью perl -MShellTrace ./myscript.pl - person perlman; 02.08.2011

Нет, системная команда не помещает свою исполняемую команду ни в какие специальные переменные.

#!/usr/bin/perl
sub get_arg {return "argument$_[0]";}
my $command = './foo ' . join(' ', get_arg(1), get_arg(2));
print "$command\n";
my $resp = `$command`; # or system($command);
print `ls *bar*`;
person Victor Bruno    schedule 02.08.2011
comment
Отредактировано для уточнения - сценарий неизменен. Я ищу решение, аналогичное strace. - person spraff; 02.08.2011