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