在 Perl 中使用 awk 解析两个字符串之间的所有内容

Posted

技术标签:

【中文标题】在 Perl 中使用 awk 解析两个字符串之间的所有内容【英文标题】:Use awk in Perl to parse everything between two strings 【发布时间】:2013-04-20 09:13:50 【问题描述】:

我在 HP-UX 服务器上不断更新大量日志文件。我创建了 Perl 代码来找出我正在使用的字符串所在的日志文件的名称。 Perl 使用 split 获取文件名并将其传递给变量。使用用户输入我将开始和停止字符串创建为两个变量。例如:

my $ssh = Net::OpenSSH->new($host, user => $user,
        master_opts => [ -o => 'NumberOfPasswordPrompts=1',
                         -o => 'PreferredAuthentications=keyboard-interactive,password'],
login_handler => \&login_handler);

$ssh-> error and die "Unable to connect" . $ssh->error;
my $output=$ssh->capture("grep .$userinput1. /app/bea/user_projects/domains/granite/om_ni.log*");

my $array = (split ":", $output)[0];
print "$array"."\n";

[编辑]:正如你们所要求的,上面是 $array 如何被填充的开始。下面是 awk 序列的开始:

my $a= "INFO - $userinput1";print $a;
my $b= "INFO - ProcessNode terminated... [$userinput1]";print $b;

使用 awk 作为 ssh capture 命令的一部分,它将搜索整个日志文件并捕获字符串 $a 和字符串 $b 之间的每一行,然后将所有内容放入另一个数组中。例如:

my $output2=$ssh->capture("awk -v i=$array '$a,$b' i");

这里 $array 是保存日志文件完整路径的位置,它作为传递变量完全可以正常工作。 我也尝试使用不带 -v 参数的 awk,一点也不重要。

[EDIT 2]:这是 print "$array"."\n";

的结果
/app/bea/user_projects/domains/granite/om_ni.log.2

当我运行 perl 脚本时,我得到了结果:

INFO - 28B26AD1-E959-4F5F-BD89-A7A6E601BE18INFO - ProcessNode terminated... [28B26AD1-E959-4F5F-BD89-A7A6E601BE18] syntax error The source line is 1.
The error context is
INFO - 28B26AD1-E959-4F5F-BD89-A7A6E601BE18,INFO - ProcessNode >>>  terminated. <<< ..  [28B26AD1-E959-4F5F-BD89-A7A6E601BE18]
awk: Quitting
The source line is 1. 

以某种方式指向“终止”字的错误,但即使我在整个字符串中使用转义字符,它也不在乎并返回相同的错误。

非常感谢您对此问题的任何帮助。非常感谢提前。

【问题讨论】:

很高兴看到完整的代码。你在capture之前执行$ssh-&gt;login吗? 我们看不到您的整个命令,因为您没有向我们展示$array 是什么。建议:将其添加到您的脚本print "awk -v i=$array '$a,$b' i" 并查看您尝试运行的命令的确切外观。这可能会使错误变得明显。但如果不是,请更新问题以包含您正在运行的确切命令(打印语句的输出)。 @DmitryMina,这是一个 Awk 错误,所以看起来 SSH 连接正在工作。 @dan1111,不确定这是否是 awk 错误,“终止”似乎更像是在 SSH 连接范围内... @dan1111 我发送的输出完全来自您建议的打印。“错误上下文是”部分之前的第一行是显示打印“$array”的位置。 【参考方案1】:

虽然我真的不知道awk,但您调用它的方式似乎并不正确。 Here is the manual for awk on HP-UX.

单引号中的部分($a,$b)应该是程序。但是,您将两个文本字符串传递给它,它们甚至没有被引用来分隔它们。这不是一个有效的 awk 程序;因此语法错误。

我认为您想要的程序类似于 '/$a/, /$b/' (但同样,我不是 awk 专家)。

此外,您将文件名设置为变量i,然后在调用命令时使用i 代替文件名。我不知道您为什么要这样做,而且我认为在文件名中使用变量甚至都行不通。只需在文件名位置使用$array(为清楚起见,您应该将其重命名为$file)。

所以你的整个命令应该是这样的:

"awk '/$a/,/$b/' $file"

在这个单一命令中,您将处理三种不同的工具:Perl、SSH 和 awk。这很难调试,因为如果出现问题,很难判断问题出在哪里。将任务分解为更小的部分以使此类工作正常进行是至关重要的。

在这种情况下,这意味着您应该手动通过 SSH 连接到服务器并使用 awk 进行操作,直到您获得正确的命令。只有当您确定您拥有正确的 awk 命令时,您才应该尝试将其合并到 Perl 中。如果你以这种方式分解任务会容易得多。

【讨论】:

嗨,丹,感谢您抽出宝贵时间帮助我。不幸的是,使用这个同义词是我尝试过的第一件事,它根本不重要。这是一个正则表达式的角度,awk 似乎不适用于 HP-UX 环境。我已经在使用 awk 的 bash 脚本上尝试了几种不同的东西,但它并没有真正起作用。我可能会将我的代码更改为单独使用 Perl 循环解析。还是非常感谢。 @MertD,如果你想让 awk 工作,如果你专门写一个关于 awk 命令的问题,有人可能会帮助你。干杯。

以上是关于在 Perl 中使用 awk 解析两个字符串之间的所有内容的主要内容,如果未能解决你的问题,请参考以下文章

如何在两个模式之间打印线,包括或不包括(在 sed、AWK 或 Perl 中)?

如何在两个模式之间打印线,包括或不包括(在 sed、AWK 或 Perl 中)?

如何在两种模式之间打印行,包括或排他(在sed,AWK或Perl中)?

如何在 sed 和 awk(和 perl)中搜索和替换任意文字字符串

搜索日志文件以获取 2 个纪元时间之间的条目范围

如何使用awk在两个连续行的字符串之间插入文本