Запустите команду Unix из сценария Perl - PullRequest
0 голосов
/ 05 ноября 2018

Я пытаюсь выполнить ssh на сервере, а затем выполнить grep, чтобы получить количество различных ошибок в файле журнала. Как только у меня есть эти данные, они заносятся в файл CSV. Но когда я пытаюсь запустить команду grep, я получаю сообщение об ошибке.

#!/usr/bin/perl
my $addr = "user\@servername";
my $text = qq|Internal Server Error|;
my $remote_path = "/data/logs/error";
my $cmd = `ssh $remote_addr "grep -a $text $remote_path | awk -F " " '{print $4}' | sort -nr | uniq -c | sort -nr 2>/dev/null"`;
print $cmd;

Но я получаю ошибку ниже, когда я запускаю скрипт

grep: Internal: No such file or directory
grep: Server: No such file or directory
grep: Error: No such file or directory

Есть ли какие-либо предположения, как мы можем сделать это в сценарии оболочки.

1 Ответ

0 голосов
/ 06 ноября 2018

Во-первых, чтобы избежать кошмара цитирования и большого количества шансов для внедрения оболочки, я бы предложил использовать такой модуль, как 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, когда файлы огромны, поскольку для этого не требуется загружать весь файл одновременно и для его скорости. Однако в этом конвейере данные передаются по каналу и вызываются повторно, поэтому эти преимущества не применяются.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...