Во-первых, чтобы избежать кошмара цитирования и большого количества шансов для внедрения оболочки, я бы предложил использовать такой модуль, как String :: ShellQuote
Тогда я не вижу, что вам нужны все эти внешние инструменты, в то время как такой длинный трубопровод сложен и дорог. Он запускает несколько программ для задач, которые действительно хорошо выполняются в Perl, и требует очень точного синтаксиса.
Помимо ssh
-ing, еще одна вещь, для которой может пригодиться внешний инструмент, - это извлечь интересующие строки с помощью grep
, в случае, если этот файл огромен (в противном случае вы можете прочитать его в скаляр) ,
use warnings;
use strict;
use feature 'say';
use List::Util qw(uniq); # in List::MoreUtils prior to module v1.45
use String::ShellQuote qw(shell_quote);
my $remote_addr = ...
my $remote_path = ...
my $text = 'Internal Server Error';
my $remote_cmd = shell_quote('grep', '-a', $text, $remote_path);
my $cmd = shell_quote('ssh', $remote_addr, $remote_cmd);
my @lines = qx($cmd);
chomp @lines;
# Process @lines as needed, perhaps
my @result = sort { $b <=> $a } uniq map { (split)[3] } @lines;
say for @result;
Когда дело доходит до запуска внешних команд, есть много опций. В первую очередь рассмотрите возможность использования модуля. Все они значительно упрощают ситуацию, в частности, с помощью проверки ошибок, и в целом более надежны, а некоторые также делают более сложные задания гораздо более управляемыми.
Пример с IPC :: System :: Simple
use IPC::System::Simple qw(capturex);
my @lines = capturex('ssh', $remote_addr, $remote_cmd);
Поскольку ssh
выполняет команду при запуске с одним, ей не требуется оболочка (для этой части), поэтому используется capturex
. См. Документацию для получения дополнительных опций и для проверки ошибок.
Некоторые другие опции, от простого до более мощного: Capture :: Tiny , IPC :: Run3 , IPC :: Run .
Подробнее об этом см. Ссылки, собранные в этом посте (и поиск более).
Я не вижу необходимости запускать этот конвейер в том виде, в каком он стоит & dagger; , но если он есть (остаться на удаленном хосте?), Тогда сформируйте команды, как указано выше, а затем соберите полный конвейер
my $cgrep = shell_quote('grep', '-a', $text, $remote_path);
my $cawk = shell_quote('awk', '-F', ' ', '{print $4}');
my $csort = shell_quote('sort', '-nr');
my $cuniq = shell_quote('uniq', '-c');
my $remote_cmd = "$cgrep | $cawk | $csort | $cuniq | $csort 2>/dev/null";
Обратите внимание, что необходимые функции оболочки (|
и перенаправление) не должны указываться в кавычках.
Простое пространство в фигуре awk
может показаться неловким, но, поскольку его экранируют, оно заводится прямо на -F
. Для меня это еще один признак проблем с запуском внешних программ в конвейерах оболочки; Я не мог понять это пустое место, спасибо Чарльзу Даффи за комментарий.
В этом случае части конвейера sort
и uniq
могут быть просто напечатаны как одна строка, так как это только имена программ и опции, но как только изменения сделаны или какие-то переменные пробиваются в этом, становится сложно , Поэтому я использую shell_quote
, для согласованности и в качестве шаблона.
Модули отсутствуют и их трудно получить. Затем избегайте того, что нужно избегать (пока вы не выясните, как получить модули, то есть). В этом случае, оказывается, мало что можно исправить, но этот бит может служить примером распространенных обручей, которые нужно пройти через сложные конвейеры.
Строка с $text
должна достигать grep
как таковая, одна строка. Поскольку он проходит через оболочку, которая разделяет его пробелами на слова, мы должны защищать (цитировать / экранировать) эти пробелы. Чтобы не забыть, мы также должны сначала получить его в оболочку, используя правила парсинга Perl.
В одну сторону
my $text_quoted = q(') . quotemeta($text) . q(');
, где quotemeta также цитирует все другие вещи.
Мы также должны защищать шаблон имени файла, так как он может опираться на метасимволы оболочки (например, *
)
my $remote_path_quoted = quotemeta $remote_path;
но опять же, вы должны проверить, подходит ли это в каждом конкретном случае.
ПРИМЕЧАНИЕ & hairsp; Если какие-либо динамически сгенерированные переменные (вычисленные, полученные от пользователя ...) интерполируются в этих командах, они должны быть проверены, с вещами, тщательно экранированными и заключенными в кавычки .
Теперь ваш конвейер должен работать (это работает в моих смоделированных тестах)
my $cmd = "ssh $remote_host grep -a $text_quoted $remote_path_quoted"
. q( | awk F ' ' '{print $4}' | sort -nr | uniq | sort -nr 2>/dev/null);
Это можно разбить на разумные компоненты в их собственных переменных и т. Д., Но я действительно не рекомендую такие исправленные вручную решения.
Я предлагаю использовать только первую часть (ssh + grep) и делать все остальное в Perl, как и в основной части ответа. Затем установите эти модули и переключитесь на них.
Ни один крупный вычислительный инструмент не работает без (многих) библиотек, и каждая производственная установка содержит много «дополнительных» вещей. По мере необходимости в дополнительных библиотеках они устанавливаются. Почему это должно быть иначе с Perl? Да, вы можете делать это только со встроенными функциями, но это может быть намного сложнее.
& dagger; & hairsp; Одной из веских причин может быть использование системы sort
, когда файлы огромны, поскольку для этого не требуется загружать весь файл одновременно и для его скорости. Однако в этом конвейере данные передаются по каналу и вызываются повторно, поэтому эти преимущества не применяются.