匹配第一个模式后Grepping第二个模式

Grepping second pattern after matching first pattern

是否有任何 grep/sed 选项允许我在匹配另一个模式后匹配一个模式?例如:输入文件(foos是以0开头的可变模式混合前面有#的随机数:

0foo1  
0foo2  
0foo3  
\#89888  
0foo4  
0foo5  
\#98980  
 0foo6

因此,一旦我尝试搜索可变模式(例如 foo2),我还想从该模式行号匹配另一个模式(例如,#number),在这种情况下, #89888.

因此变量 foo2 的输出必须是:

foo2  #89888

对于变量 foo5:

foo5  #98980

foos 由每个字符组成,包括可被视为元字符的字符。

我尝试了一个使用 tcl 的基本正则表达式匹配脚本,它将首先搜索 foo*,然后搜索下一个直接 #,但是由于我正在处理一个非常大的文件,它需要天完成。感谢任何帮助。

#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;

my ( %matches, $recent_foo );

while(<DATA>)
{
   chomp;
   ( $matches{$recent_foo} ) =  if m/(\#\d+)/;
   ( $recent_foo ) =  if m/(0foo\d+)/;
}

print Dumper( \%matches );

__DATA__
0foo1  
0foo2  
0foo3  
\#89888  
0foo4  
0foo5  
\#98980  
 0foo6

 ./perl 
$VAR1 = {
          '0foo5' => '\#98980',
          '0foo3' => '\#89888'
        };

一个 Perl 单行代码,用于 slurp 整个文件并匹配您要查找的模式的任何换行符,如下所示:

perl -000  -nle 'm{(foo2).*(\#89888)}s and print join " ",,' file

-000 开关启用 "slurp" 模式,该模式指示 Perl 不要将文件分成块,而是将其视为一个大字符串。 s 修饰符让 . 匹配任何字符,包括换行符。

如果您想要 0foo10foo20foo3 都具有相同的值,则执行以下操作:

#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;

my ( %matches, @recent_foo );

while(<DATA>)
{
   chomp;
   if (/^\#/)
   {
     @matches{@recent_foo} = ($') x @recent_foo;
     undef @recent_foo;
   }
   elsif (/^0/)
   {
     push @recent_foo, $';
   }
}

print Dumper( \%matches );

__DATA__
0foo1
0foo2
0foo3
\#89888
0foo4
0foo5
\#98980
0foo6

给出:

$VAR1 = {
          'foo2' => '89888',
          'foo1' => '89888',
          'foo5' => '98980',
          'foo3' => '89888',
          'foo4' => '98980'
        };
Var='foo2'
sed "#n
/${Var}/,/#[0-9]\{1,\}/ {
   H
   /#[0-9]\{1,\}/ !d
   s/.*//;x
   s/.//;s/\n.*\n/ /p
   q
   }" YourFile

要求不明确。它首先出现你的模式 foo2 直到第一个 #number,删除之间的线并在 1 中打印两行而不是退出(没有其他提取物

Tcl 解决方案。该过程 运行 只需 3 微秒多一点,因此您需要 非常 大数据文件才能 运行 几天。如果多个标记匹配,则使用第一个匹配(很容易将过程重写为 return 所有匹配)。

set data {
0foo1  
0foo2  
0foo3  
\#89888  
0foo4  
0foo5  
\#98980  
 0foo6
}

proc find {data pattern} {
    set idx [lsearch -regexp $data $pattern]
    if {$idx >= 0} {
        lrange $data $idx $idx+1
    }
}

find $data 0foo3
# -> 0foo3 #89888
find $data 0f.*5
# -> 0foo5 #98980

文档:if, lrange, lsearch, proc, set

sed

sed -n '/foo2/,/#[0-9]\+/ {s/^[[:space:]]*[0\]//; p}' file | 
sed -n '1p; $p' | 
paste -s
  • 第一个 sed 打印第一个模式和第二个模式之间的所有行,删除可选的前导空格和前导 0\
  • 第二个 sed 只提取第一行和最后一行。
  • 粘贴命令将 2 行打印为一行,用制表符分隔。

awk

awk -v p1=foo5 '
    [=11=] ~ p1 {found = 1} 
    found && /#[0-9]+/ { sub(/^\\/, ""); print p1, [=11=]; exit }
' file

tcl

lassign $argv filename pattern1
set found false
set fid [open $filename r]
while {[gets $fid line] != -1} {
    if {[string match "*$pattern1*" $line]} {
        set found true
    }
    if {$found && [regexp {#\d+} $line number]} {
        puts "$pattern1 $number"
        break
    }
}
close $fid

然后

$ tclsh 2patt.tcl file foo4
foo4 #98980

这是你想要的吗?

$ awk -v tgt="foo2" 'index([=10=],tgt){f=1} f&&/#[0-9]/{print tgt, [=10=]; exit}' file
foo2 \#89888

$ awk -v tgt="foo5" 'index([=10=],tgt){f=1} f&&/#[0-9]/{print tgt, [=10=]; exit}' file
foo5 \#98980

我在上面使用 index(),因为它搜索的是字符串而不是正则表达式,所以我不在乎 foo 中的 RE 元字符是什么 - 它们都只是字符串中的文字字符。

从你的问题中不清楚你是想在特定 foo 之后查找特定数字还是在 foo2 之后查找第一个数字,或者即使你想搜索特定 foo 值或所有 "foo" 或...