【问题标题】:Awk - Printing n last, interspersed lines containing keywordawk - 打印最后 n 个包含关键字的散布行
【发布时间】:2019-07-01 12:24:27
【问题描述】:

假设一个多行文本文件file,其中一些行以关键字baz 开头。

$ cat file
foo bar
baz qux   # line to be deleted
foo bar
foo bar baz
baz
baz qux quux
foo bar

如何显示所有不以关键字开头的行以及n 以关键字开头的最后一行?

如果 n=2,结果应如下所示:

$ sought_command file
foo bar
foo bar
foo bar baz
baz
baz qux quux
foo bar

我相信 awk 可能是这里的方法。大致如下:

counter=1
tac file | awk '{
if ($1 =="baz" && counter<=2)
    {print $0; counter=$((counter+1));}
else if ($1 =="baz" && counter>2)
    {next;}
else
    {print $0;}
}' | tac

我需要在上面的代码中进行哪些更改才能使其正常工作?

【问题讨论】:

  • 这个逻辑是如何工作的?最后几行仍然以baz 开头?有没有可能你指的是一半和另一半
  • Awk 不知道有一个 Bash 变量也名为 counter
  • @Inian 输出应该正好包含以关键字开头的两行,即输入的最后两行 baz 起始行。

标签: bash text awk reverse tac


【解决方案1】:

您不能从 Awk 操作或访问 Bash 变量,就像您不能从 Bash 访问 C 程序中的变量一样。

tac file |
awk '$1 =="baz" && ++counter<=2 {print; next}
     $1 !="baz"' |
tac

【讨论】:

  • 感谢您指出 awk 无法读取 shell 变量。话虽如此,您建议的代码不会仅打印以关键字开头的最后 n 行。相反,它会复制以关键字开头的最后一行。可以修改一下吗?
  • 很抱歉,删除了有问题的换行符。这实际上只是对您的脚本的重构,所以我懒得实际测试。
【解决方案2】:
$ tac file | awk '$1!="baz" || c++<2' | tac
foo bar
foo bar
foo bar baz
baz
baz qux quux
foo bar

【讨论】:

    【解决方案3】:

    如果您想尝试 Perl,这里有一个独立的解决方案。

    $ cat michael.txt
    foo bar
    baz qux   # line to be deleted
    foo bar
    foo bar baz
    baz
    baz qux quux
    foo bar
    $ perl -0777 -ne ' $x++ for(/^baz/gm); $y=$x-2; while( $y-- ) { s/^baz.+?\n//m } ; print ' michael.txt
    foo bar
    foo bar
    foo bar baz
    baz
    baz qux quux
    foo bar
    $
    

    【讨论】:

      猜你喜欢
      • 2014-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-09-23
      • 1970-01-01
      • 2019-11-06
      • 2011-01-03
      相关资源
      最近更新 更多