grep 一个模式和 return 另一个特定字符前后的所有字符 bash

grep a pattern and return all characters before and after another specific character bash

我有兴趣在日志文件中搜索变量,以防搜索 returns 什么然后我希望在变量之前的所有条目,直到遇到字符 '{' 和模式之后直到遇到字符'}'。

为了更准确,让我们来看下面的例子:

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 上找东西。我只能想出用于查找模式的选项,然后 return 所有行,直到满足 '}',但是我找不到适合模式之前的行的解决方案。

我在 Perl 中找到了一个可以使用的正则表达式,但我无法使用该变量,如果我用 'foo' 切换变量,那么我将有输出。

grep -Poz '.*(?s)\{[^}]*name\tfoo.*?\}'

正则表达式非常简单,一旦将整个文件读入变量

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

die "Usage: [=10=] filename\n" if not @ARGV;

my $file_content = do { local $/; <> };  # "slurp" file with given name

my $target = qr{name foo};

while ( $file_content =~ /({ .*? $target .*? })/gsx ) { 
    say ; 
}

因为我们 undef-ine input record separator inside the do block using local, the following read via the null filehandle <> 一次拉取整个文件,作为一个字符串(“slurps”它)。它由 do 块返回并分配给变量。 <> 从名称在 @ARGV 中的文件中读取,因此在程序调用时在命令行上提交了什么。

在正则表达式模式中,? 量词使 .* 仅匹配下一个子模式的第一次出现,因此在 { 之后 .*? 匹配到第一个 $target,然后匹配(评估的)$target,然后 .*? 匹配直到第一个 } 的所有内容。所有通过包含 () 捕获的内容因此稍后在 </code>.</p> 中可用 <p> <code>/s 修饰符使 . 匹配换行符,它通常不会匹配换行符,这是匹配涉及多行的模式所必需的。使用 /g 修饰符,它会不断遍历内容。 /x 空格不匹配,因此我们可以展开模式以提高可读性。

$target 使用 qr 运算符编译为正确的正则表达式模式。

参见正则表达式教程 perlretut, and then there's the full reference perlre

这是一个 Awk 尝试,试图从字里行间中读出实际需求。我猜你想说的是“如果有左大括号,打印它和右大括号之间的所有内容,以防大括号内匹配。否则,只打印匹配的行。”

我们通过在 Awk 中创建一个状态变量来实现这一点,该变量跟踪您是否处于大括号上下文中。这个简单的实现不会正确处理嵌套的大括号;如果那是你的要求,也许 post 一个新的更好的问题与你的 实际 要求。

awk -v search="foo" 'n { context[++n] = [=10=] }
    /{/ { delete context; n=0; matched=0; context[++n] = [=10=] }
    /}/ && n { if (matched) for (i=1; i<=n; i++) print context[i];
        delete context; n=0 }
    [=10=] ~ search { if(n) matched=1; else print }' file

变量n为采集数组的行数context;当它为零时,我们不在大括号之间的上下文中。如果我们找到一个匹配项并将行收集到 context,则推迟打印直到我们收集了整个 context。否则,只打印当前行。