考虑以下文本文件
one 1
two 2
three 3
four 4
five 5
six 6
seven 7
eight 8
我想访问匹配行之后的第二行four
。这将是以下行
six 6
然后,结果行(即上面的行)将被传输以进行进一步处理(例如,a | cut -d' ' -f2
)。
有没有办法在 bash 和其他典型实用程序中做到这一点?(否则我将用 Python 编写脚本)
编辑:在我的特定情况下,(举个例子)的出现four
保证是唯一的。但答案显示了有趣的扩展情况,但事实并非如此。
答案1
前两个答案并没有错,但我想让你知道,在一次sed
调用中就可以找到模式后的第三行:
sed -n "/four/ { n; n; p }" SourceData.txt
因为单个程序可以完成这项工作,所以这比运行多个过滤器更有效率。上述命令在每次出现“four”后都会输出第三行,除非在匹配后的两行之一中再次出现这种情况(其他解决方案也不会以预期的方式处理这种情况);此外,如果模式位于文件的最后一行或倒数第二行,则不会生成任何输出,这可能是也可能不是您想要的。
仅匹配第一个实例:
sed -n "/four/ { n; n; p; q }" SourceData.txt
(请注意,这个答案尽可能高效,因为一旦找到匹配就结束扫描。)
我添加这个解决方案是因为它值得了解sed
,尽管它的语法相当令人反感(正则表达式已经够糟糕了!),但它通常非常有用。这教程是一个很好的介绍。
答案2
注意:这个答案最初是在 OP 明确说明模式只出现一次之前写的。它被设计为不会错过任何出现的情况(除非接近结尾,所以没有“第 n 行之后”),我将保留它。如果您确定只出现一次,或者如果您只希望找到第一个,您可以考虑其他立即停止并且不解析整个输入流/文件的解决方案徒然。
此解决方案打印当前行,当且仅当两行之前有匹配项。它与其他一些答案略有不同,因为它不会错过另一个匹配项,即使该匹配项在上一个匹配项之后不久发生。
awk -v delay=2 '{for (i=delay; i>=0; i--) t[i]=t[i-1]} /four/ {t[0]="m"} {if (t[delay]) print}'
只要有匹配项,信息就会存储在 中t[0]
。每行t
数组都会移动一次(包括移动t[-1]
到t[0]
以重置 的值t[0]
)。当且仅当数组指示两行之前有匹配项时,才会打印该行。
您可以轻松设置不同的延迟(例如delay=7
)或使用其他模式(例如/sda[[:digit:]]/
)
答案3
您可以使用以下表达式(input.txt
):
grep "four" -A 2 input.txt | tail -n 1
输出为:
six 6
选项grep
“-A 2”表示输出匹配行后的两行。
选项tail
“-n 1”表示只1
返回此结果的最后几行。
答案4
对于多次出现的情况,并假设没有行以 开头--
:
( grep -A 2 pattern data.txt; echo '--' ) | grep -E -B1 '^--' | grep -Ev '^--'
慢动作:
( grep -A 2 pattern data.txt; echo '--' )
打印模式和接下来的两行,并--
在组之间插入一行。echo '--'
确保最后一组后面也跟着--
。grep -E -B1 '^--'
打印分隔符和之前的行(这就是我们要找的)grep -Ev '^--'
删除分隔符,仅留下我们正在寻找的行。