Perl脚本运行Unix命令(Run Unix command from a perl Script

2019-11-05 07:35发布

我试图做一个服务器上的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

是否有任何建议,我们如何在shell脚本做到这一点。

Answer 1:

首先,为了避免引用噩梦和很多机会壳注入我建议使用一个模块,如字符串:: 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 ::系统::简单

use IPC::System::Simple qw(capturex); 

my @lines = capturex('ssh', $remote_addr, $remote_cmd);

由于ssh当与一个不需要一个外壳(该部分),以便运行执行该命令capturex被使用。 有关详情,请选项和如何检查错误文件。

一些其他的选择,从简单到更强大,是捕捉::微小 , IPC :: RUN3 , IPC ::运行 。

欲了解更多有关这一切看到组装环节这篇文章 (和寻找更多)。


我看不到一个需要运行的管道,因为它代表但如果有一个(留在远程主机上的?)然后形成如上命令,然后组装完整的管道

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 。 对于我来说,与运行在外壳管道外部程序麻烦的另一个迹象; 我无法弄清楚裸空间,感谢查尔斯·达菲的评论。

在这种情况下, sortuniq管道部分可以刚才输入作为一个字符串,因为它是唯一的程序名称和选项,但只要更改时或任何变量,使他们以这种方式变得非常棘手。 所以我用shell_quote ,一致性和作为模板。


模块失踪,很难获得。 然后逃逸有什么需要进行转义(直到你找出如何让这些模块,这是)。 在这种情况下,正好是小解决,但该位可作为普通篮球的例子复杂的管道要经过。

以字符串$text需要达到grep正因为如此,一个字符串。 由于它穿过外壳,这将打破它通过空间分成的话,我们需要保护(报价/退出)的处所。 更不要忘了,我们还需要得到它摆在首位的外壳,通过Perl的解析规则。

单程

my $text_quoted = q(') . quotemeta($text) . q(');

其中quotemeta引用各种其他事情也是如此。

我们也应该保护的文件名模式,因为它可能会依赖于shell元字符(如*

my $remote_path_quoted = quotemeta $remote_path;

但同样,你要检查一下是否适合在各种情况下。

注意如果任何动态生成的变量(计算,来自用户的...)都插在这些命令,他们需要被验证,事情仔细逃脱并引述

现在你应该管的工作(它在我的模拟试题)

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不同? 是的,你可以只用内建做,但可能更难。


一个很好的理由会如此使用系统sort时,文件是巨大的,因为它没有加载整个文件一次,并且它的速度。 然而,这条管线是在管道提供的数据和重复调用等等这些优势并不适用。



文章来源: Run Unix command from a perl Script
标签: shell perl