如何获取从最后匹配到文件结尾的行?

时间:2019-05-28 01:58:57

标签: shell awk sed grep

需要在最后一次匹配到文件末尾之后打印行。比赛的数量可以是任意的,而不是确定的。我有一些文字,如下所示。

MARKER
aaa
bbb
ccc
MARKER
ddd
eee
fff
MARKER
ggg
hhh
iii
MARKER
jjj
kkk
lll

所需的输出是

jjj
kkk
lll

我将awk与RS和FS一起使用以获得所需的输出吗?

5 个答案:

答案 0 :(得分:6)

实际上,您可以使用awk(gawk)进行操作,而无需使用任何管道。

$ awk -v RS='(^|\n)MARKER\n' 'END{printf "%s", $0}' file
jjj
kkk
lll

说明:

  • 您通过(^|\n)MARKER\n将记录分隔符定义为RS='(^|\n)MARKER\n',默认情况下为EOL字符
  • 'END{printf "%s", $0}' =>在文件末尾,您将打印整行,因为RS被设置为(^|\n)MARKER\n$0将包括所有行,直到EOF 。


另一种选择是使用grep(GNU):

$ grep -zoP '(?<=MARKER\n)(?:(?!MARKER)[^\0])+\Z' file
jjj
kkk
lll

说明:

  • -z使用ASCII NUL字符作为分隔符
  • -o仅打印匹配项
  • -P激活perl模式
  • PCRE正则表达式:(?<=MARKER\n)(?:(?!MARKER)[^\0])+\Z在这里https://regex101.com/r/RpQBUV/2/


最后但并非最不重要的一点,还可以使用以下sed方法:

sed -n '/^MARKER$/{n;h;b};H;${x;p}' file
jjj
kkk
lll

说明:

  • n跳至下一行
  • h用当前行替换保留空间
  • H执行相同的操作,但不要替换,而是添加
  • ${x;p}在文件交换(x)结束时保留空间和图案空间并打印(p

可以变成:

tac file |  sed -n '/^MARKER$/q;p' | tac

如果我们使用tac

答案 1 :(得分:3)

请您尝试以下。

tac file | awk '/MARKER/{print val;exit} {val=(val?val ORS:"")$0}' | tac

此方法的好处是awk只会读取Input_file的最后一块(实际上,这是awk的第一个块,tac反向打印之后),然后退出。

说明:

tac file |                      ##Printing Input_file in reverse order.
awk '
  /MARKER/{                     ##Searching for a string MARKER in a line of Input_file.
    print val                   ##Printing variable val here. Because we need last occurrence of string MARKER,which has become first instance after reversing the Input_file.
    exit                        ##Using exit to exit from awk program itself.
  }
  {
    val=(val?val ORS:"")$0      ##Creating variable named val whose value will be keep appending to its own value with a new line to get values before string MARKER as per OP question.
  }
' |                             ##Sending output of awk command to tac again to make it in its actual form, since tac prints it in reverse order. 
tac                             ##Using tac to make it in correct order(lines were reversed because of previous tac).

答案 2 :(得分:1)

这可能对您有用(GNU sed):

sed -nz 's/.*MARKER.//p' file

这使用贪婪删除所有行,包括最后一次出现的MARKER

答案 3 :(得分:0)

您也可以尝试Perl

$ perl -0777 -ne ' /.*MARKER(.*)/s and print $1 ' input.txt

jjj
kkk
lll

$

答案 4 :(得分:0)

最容易记住:

tac fun.log | sed "/MARKER/Q" | tac