在另外两行之间搜索一行(字符串)

在另外两行之间搜索一行(字符串)

我正在寻找一个可以查找其他两行之间是否存在特定字符串/行的一行命令(最佳方式)。我搜索了它,但只找到了用于获取两行之间内容的命令,但我如何检查是否存在某些内容?

.....
 1 a 2 b 3
 4
   5
.....
 1 c 2 d 3
 4
   5
.....
 1 e 2 f 3
   5
.....

我找到了这个:

sed -n '/^ 1 .* 2 .* 3$/,/^ 5$/p'

使用此命令的结果是剪掉了不需要的线条,这对于开始来说是件好事(剪掉了线条“....”),但仍然不知道如何检查是否存在“4”:

 1 a 2 b 3
 4
   5
 1 c 2 d 3
 4
   5
 1 e 2 f 3
   5

输出应如下所示:

 "4" is missing after "1 e 2 f 3"

或仅(甚至更好):

"1 e 2 f 3"

答案1

sed不是适合这项工作的工具。但是,我们仍然可以这样做sed

sed -n '/^ 1 .* 2 .* 3$/,/^ 5$/ { /^ 1 .* 2 .* 3$/ { h }; /^ 4$/ { x; s/.*//; x;}; /^ 5$/ { x; p; x} }' filename | grep -v -e '^$'

以下仅是我添加到范围块中的部分:

/^ 1 .* 2 .* 3$/ { h }; /^ 4$/ { x; s/.*//; x;}; /^ 5$/ { x; p; x}

读作:

如果行与正则表达式匹配/^ 1 .* 2 .* 3$/,则h(将行存储到保持缓冲区)
如果行与正则表达式匹配/^ 4$/,则x(交换缓冲区,即,使操作应用于保持缓冲区而不是标准缓冲区),然后替换保持缓冲区中的所有内容*,然后x再次(切换回标准缓冲区)
如果行与正则表达式匹配^ 5$/,则切换到保持缓冲区,p(打印保持缓冲区的内容),然后切换回标准缓冲区

* 遗憾的是,s/.*//不会删除保持缓冲区中的行。删除保持缓冲区中的行似乎很困难,因此我们grep -v -e '^$'改为通过管道插入来删除它们。

更新

此版本在匹配后打印文件名(使用F命令),并且无需通过管道传输grep。谢谢你,Paulo!

sed -n '/^ 1 .* 2 .* 3$/,/^ 5$/ { /^ 1 .* 2 .* 3$/ { h }; /^ 4$/ { x; s/.*//; x;}; /^ 5$/ { x; /^$/ !{ p; F }; x} }' data

答案2

谢谢@斯尼普值得一提的是perl

perl -lane 'if($n=/^ 1 .* 2 .* 3$/../^ *5$/) {$s=$_ if $n==1; $s="" if /^ *4$/; print "$ARGV: $s" if $s && $n=~/E/}' /otherdir/*

我希望我理解正确了这个问题:请添加到 OP 中以指定任何进一步的详细信息。

解释:

perl实用的提取和报告语言。
-lane通常对单行有用的开关。
'实际程序指令的开始
•仅对以行匹配开头并以包含单个数字的行结尾的if(/^ 1 .* 2 .* 3$/../^ *5$/) {文本执行花括号之间的操作,该行可能前面有任意数量的空格。 •跟踪文本部分内的行号。 •将文本部分的第一行保存在变量中。 •查找所需的字符串:在任意数量的空格之后的单个数字。如果找到,则删除变量的先前保存的行。 •如果变量包含任何文本并且计数器显示已到达文本部分的最后一行,则打印文件名、冒号、空格和开始当前文本部分的行。 •对文本部分执行的操作的结束。 •程序指令的结束。 •处理路径中的所有文件/^ 1 .* 2 .* 3$/5
$n=/^ 1 .* 2 .* 3$/../^ *5$/
$s=$_ if $n==1;$s
$s="" if /^ *4$/;4$s
print "$ARGV: $s" if $s && $n=~/E/$s$n
}
'
/otherdir/*/otherdir/

相关内容