在Perl中发送Linux命令-Grep通过管道传递到grep

时间:2018-07-19 09:29:37

标签: linux perl grep command pipe

基本代码:

my $ContentDate = `date -d '1 hour ago' '+%Y-%m-%e %H:'`;
my $Fail2banNo = `grep Ban /var/log/fail2ban.log | grep $ContentDate | wc -l`;

if (($Fail2banNo > $fail2ban)) {

} else {

}

为什么Perl无法正确完成这些命令? $ fail2ban已经定义为0,所以这不是问题。

fail2ban.log确实包含应该匹配的行(当从shell运行命令时,它匹配):

2018-07-19 xx:11:50,200 fail2ban.actions[3725]: WARNING [iptables] Ban x.x.x.x

我一直遇到的错误是:

grep: 10:: No such file or directory
sh: -c: line 1: syntax error near unexpected token `|'
sh: -c: line 1: ` | wc -l'
Argument "" isn't numeric in numeric gt (>) at /usr/local/bin/tmgSupervision.pl line 3431.

所有命令都可以从bash / shell正常运行,似乎是如果perl不满意将grep传递到另一个grep吗?我尝试了许多不需帮助就将变量($ ContentDate)添加到grep的方法。

3 个答案:

答案 0 :(得分:6)

我注意到您接受的答案在一个小时前计算时间戳的方法非常复杂,因此我提出了这种替代方法,它以更有效的方式使用Perl的内置日期和时间处理。

#!/usr/bin/perl

use strict;
use warnings;
use feature 'say';

use Time::Piece;

my $log = '/var/log/fail2ban.log';
my $fail2ban = 0;

my $ContentDate = localtime(time - 3600)->strftime('%Y-%m-%e %H:');
my $Fail2banNo = qx{grep Ban $log | grep "$ContentDate" | wc -l};

if ($Fail2banNo > $fail2ban) {
  say 'Yes';
}
else {
  say 'No';
}

但是您真正需要的唯一更改是更改:

my $Fail2banNo = `grep Ban /var/log/fail2ban.log | grep $ContentDate | wc -l`;

收件人:

my $Fail2banNo = `grep Ban /var/log/fail2ban.log | grep "$ContentDate" | wc -l`;

引用$ContentDate,因为其中包含空格。

答案 1 :(得分:1)

第一个问题是$ContentDate以换行结尾。

第二个问题是您不正确地从$ContentDate创建了shell文字(使用grep 2018-07-19 08:而不是类似grep '2018-07-19 08:'的东西)。

让我们先解决您的问题。

use String::ShellQuote qw( shell_quote );

my $fail2ban_log_qfn = '/var/log/fail2ban.log';

my $content_date = `date -d '1 hour ago' '+%Y-%m-%e %H:'`;
chomp($content_date);

my $grep_cmd1 = shell_quote('grep', 'Ban', $fail2ban_log_qfn);
my $grep_cmd2 = shell_quote('grep', '--', $content_date);
my $fail2ban_count = `$grep_cmd1 | $grep_cmd2 | wc -l`;
chomp($fail2ban_count);

不过,无需花时间就可以获取日期。

use POSIX              qw( strftime );
use String::ShellQuote qw( shell_quote );

my $fail2ban_log_qfn = '/var/log/fail2ban.log';

my $content_date = strftime('%Y-%m-%e %H:', localtime(time - 3600));

my $grep_cmd1 = shell_quote('grep', 'Ban', $fail2ban_log_qfn);
my $grep_cmd2 = shell_quote('grep', '--', $content_date);
my $fail2ban_count = `$grep_cmd1 | $grep_cmd2 | wc -l`;
chomp($fail2ban_count);

也无需花一些时间来计算匹配行。

use POSIX qw( strftime );

my $fail2ban_log_qfn = '/var/log/fail2ban.log';

my $fail2ban_count = 0;
{
   my $content_date = strftime('%Y-%m-%e %H:', localtime(time - 3600));

   open(my $fh, '<', $log_qfn)
      or die("Can't open \"$fail2ban_log_qfn\": $!\n");

   while (<$fh>) {
      ++$fail2ban_count if /Ban/ && /\Q$content_date/;
   }
}

答案 2 :(得分:-4)

尝试一下

#!/usr/bin/perl

use strict;
use warnings;
use feature 'say';

my $log = "/var/log/fail2ban.log";
my $fail2ban = 0;

my $ContentDate = backintime(3600); #backintime in seconds from now
my $Fail2banNo = qx{grep Ban $log | grep \"$ContentDate\"| wc -l};

if ($Fail2banNo > $fail2ban) {
        say "Yes";
}
else {
        say "No";

}


sub backintime {
        my ($to_today) = @_;
        my $temps = time - 60*60*24*0;
        $temps = $temps - $to_today;
        my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($temps);
        if($sec < 10) {$sec = "0" . $sec;}
        if($min < 10) {$min = "0" . $min;}
        if($hour < 10) {$hour = "0" . $hour;}
        if($mday < 10) {$mday = "0" . $mday;}
        $year+=1900; $mon++; if($mon < 10) {$mon = "0" . $mon;}
        my $sectime = $year."-".$mon."-".$mday." ".$hour.":";
        return($sectime);
}