匹配第一个模式后Grepping第二个模式
Grepping second pattern after matching first pattern
是否有任何 grep/sed 选项允许我在匹配另一个模式后匹配一个模式?例如:输入文件(foo
s是以0
开头的可变模式混合前面有#
的随机数:
0foo1
0foo2
0foo3
\#89888
0foo4
0foo5
\#98980
0foo6
因此,一旦我尝试搜索可变模式(例如 foo2
),我还想从该模式行号匹配另一个模式(例如,#number
),在这种情况下, #89888
.
因此变量 foo2
的输出必须是:
foo2 #89888
对于变量 foo5
:
foo5 #98980
foo
s 由每个字符组成,包括可被视为元字符的字符。
我尝试了一个使用 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
修饰符让 .
匹配任何字符,包括换行符。
如果您想要 0foo1
、0foo2
和 0foo3
都具有相同的值,则执行以下操作:
#!/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
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" 或...
是否有任何 grep/sed 选项允许我在匹配另一个模式后匹配一个模式?例如:输入文件(foo
s是以0
开头的可变模式混合前面有#
的随机数:
0foo1
0foo2
0foo3
\#89888
0foo4
0foo5
\#98980
0foo6
因此,一旦我尝试搜索可变模式(例如 foo2
),我还想从该模式行号匹配另一个模式(例如,#number
),在这种情况下, #89888
.
因此变量 foo2
的输出必须是:
foo2 #89888
对于变量 foo5
:
foo5 #98980
foo
s 由每个字符组成,包括可被视为元字符的字符。
我尝试了一个使用 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
修饰符让 .
匹配任何字符,包括换行符。
如果您想要 0foo1
、0foo2
和 0foo3
都具有相同的值,则执行以下操作:
#!/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
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" 或...