我有兴趣在日志文件中搜索一个变量,如果搜索返回一些东西,那么我希望在变量之前找到所有条目,直到字符"{"出现,在模式之后找到字符"}"出现。
更准确地说,让我们举以下例子:
something something {
entry 1
entry 2
name foo
entry 3
entry 4
}
something something test
test1 test2
test3 test4
在这种情况下,我会搜索"name foo",它将存储在一个变量中(我之前在一个单独的部分中创建(,预期的输出将是:
{
entry 1
entry 2
name foo
entry 3
entry 4
}
我试着在grep、awk或sed上找到一些东西。我只能想出找到图案的选项,然后返回所有线条,直到满足"}",但我找不到适合图案之前线条的解决方案。
我在Perl中找到了一个可以使用的正则表达式,但我不能使用该变量,如果我用"foo"切换变量,那么我就会有输出。
grep -Poz '.*(?s){[^}]*nametfoo.*?}'
正则表达式非常简单,一旦将整个文件读取到变量中
use warnings;
use strict;
use feature 'say';
die "Usage: $0 filenamen" if not @ARGV;
my $file_content = do { local $/; <> }; # "slurp" file with given name
my $target = qr{name foo};
while ( $file_content =~ /({ .*? $target .*? })/gsx ) {
say $1;
}
由于我们使用local将输入记录分隔符undef
放入do块中,因此下面通过null文件句柄<>
读取的内容会一次将整个文件作为字符串("slurps"it(。它由do
块返回并分配给变量。<>
从名为@ARGV
的文件中读取,因此在程序调用时在命令行上提交了什么。
在正则表达式模式中,?
量词使.*
只匹配到下一个子模式的第一次出现,因此在{
之后,.*?
匹配到第一个(评估的($target
,然后匹配$target
,然后.*?
每一次匹配直到第一个}
。所有这些都是通过封装()
来捕获的,因此稍后在$1
中可用。
/s
修饰符使.
匹配换行符,它通常不匹配换行符的内容,以及匹配跨多行的模式所必需的内容。使用/g
修饰符,它会不断遍历字符串,搜索所有这样的匹配项。有了/x
,空白是不匹配的,所以为了可读性,我们可以展开模式(甚至是在行上——并使用注释!(。
使用qr运算符将$target
编译为正确的正则表达式模式。
请参阅regex教程perlreput,然后是完整的perlre参考。
这里有一个Awk尝试,它试图在行与行之间进行读取,以阐明实际的需求。我猜你想说的是";如果有一个左大括号,请打印它和右大括号之间的所有内容,以防大括号内匹配。否则,只需打印匹配的行">
我们通过在Awk中创建一个状态变量来实现这一点,该变量可以跟踪您是否处于大括号上下文中。这种简单的实现无法正确处理嵌套的大括号;如果这是您的要求,也许可以发布一个新的、更好的问题,说明您的实际要求。
awk -v search="foo" 'n { context[++n] = $0 }
/{/ { delete context; n=0; matched=0; context[++n] = $0 }
/}/ && n { if (matched) for (i=1; i<=n; i++) print context[i];
delete context; n=0 }
$0 ~ search { if(n) matched=1; else print }' file
变量CCD_ 21是所收集的阵列CCD_;当它为零时,我们不在大括号之间的上下文中。如果我们找到匹配项并将行收集到context
中,则推迟打印,直到我们收集了整个context
。否则,只打印当前行。