【问题标题】:Awk - print last 4 lines of the fileawk - 打印文件的最后 4 行
【发布时间】:2012-09-22 19:15:03
【问题描述】:

我有一个测试文件:

1
2
3
4
5
6
7
8

此命令打印文件的最后 4 行:

$ awk 'BEGIN{"wc -l < file" | getline b}{if(NR>b-4) print}' file
5 
6 
7 
8 
userpc@userpc-desktop

现在我也想做同样的事情,但是命令系统():

$ awk '{if( NR > (system("wc -l < file")-4) ) print}' file
8 
1 
8 
2 
8 
3 
8 
4 
8 
5 
8 
6 
8 
7 
8 
8 
userpc@userpc-desktop:

如何改进最后一个命令系统()?我还想打印文件的最后 4 行。 感谢您的帮助。

【问题讨论】:

  • 你为文件的每一行分叉一个wc ???像您这样的人是 4GHz、具有 64GB RAM 的 Octocore CPU 的原因:-)
  • 哦,它不起作用,因为 system() 返回退出状态(在这种情况下为 0 -> 始终为真),而不是 wc 的输出。如您所见,为每一行打印标准输出(“8”)。
  • 谢谢你的澄清,但我仍然不知道如何改进命令系统()。

标签: awk


【解决方案1】:

不需要awk,使用tail:

$ tail -4 your_file

【讨论】:

  • 谢谢,很好的回答,但问题是关于 awk 和最后一个命令。
  • 既然存在简单的解决方案,为什么还要复杂?
  • 感谢解决方案。
  • 在一般情况下,一个实用的解决方案可能是将输出从 tail 传输到 awk:tail -4 file | awk '{print}' 其中“print”可能是一些更有用的 awk 表达式。
【解决方案2】:

awk 绝对不是解决此问题的正确工具。常做:sed '1{N;N;N;}; N; D; $p',也可以用awk做类似的事情:

awk '{for( i=0;i<3;i++) a[i]=a[i+1];a[3]=$0} END {print a[0],a[1],a[2],a[3]}' OFS='\n'

基本上,您会跟踪看到的最后四行,并在到达文件末尾时将它们全部打印出来。您可以通过以下方式变得更加晦涩和高效:

awk '{a[++i%4]=$0} END {print a[++i%4],a[++i%4],a[++i%4],a[++i%4]}' OFS='\n'

但是,真的,你为什么要这样做?

【讨论】:

  • 很好的解决方案,但用于打印少量行。如果我打印的行数越多,命令就会越长。
  • 其实,这是一个糟糕的解决方案!但是,如果您使用带有 for 循环的第二种形式,它确实可以很好地扩展。即awk '{a[++i%n]=$0} END {for(j=0;j&lt;n;j++) print a[++i%n]}' n=256
  • 这个解决方案很好。不过我会等待改进我的第二个命令系统的建议()。
  • 您评论中的解决方案将是正确的方法。原理和我的回答here类似。
  • 但是,真的,你为什么要这么做?出于同样的原因,您需要文件的前 4 行。这个例子指出了 awk 作为通用工具的局限性。
【解决方案3】:

一种使用GNU awk的方式:

awk '{ array[NR]=$0 } END { for (i=NR-3; i<=NR; i++) print array[i] }' file.txt

结果:

5
6
7
8

【讨论】:

  • 感谢解决方案。
【解决方案4】:

如果您只是想要一种机制来改进您在system 中使用wc,请尝试:

awk 'NR > count-4' count=$( wc -l < file ) file

在 awk 中做更多的事情;

awk 'NR==1{ c="wc -l < " FILENAME; c | getline count } NR > count-4' input

这使用 NR==1 而不是 BEGIN,因为 FILENAME 未在 BEGIN 块内定义。 请注意,这些都不使用 awk 中的 system,因为没有从 system 获取输出的好方法,但是您可以做一些丑陋的事情,例如:

awk 'NR==1 { system( "wc -l > tmpfile < " FILENAME ); getline count < "tmpfile" }
    NR > count - 4' input

这只是一个学术练习,我怎么强调都不为过。不要为此使用 awk!

【讨论】:

  • 感谢解决方案。
【解决方案5】:

tail 是正确的工具,但如果你想在 Awk 中看到它:

awk '{b=b RS $0} b~/(\n.*){4}/{sub(/[^\n]*\n/,"",b)} END{print b}'
  1. 将行追加到缓冲区,用换行符分隔;
  2. 如果缓冲区中有 4 个换行符,则从中删除第一行;
  3. 最后,打印缓冲区。

【讨论】:

    【解决方案6】:

    这是使用tacawk 的另一种方式:

    $ tac file | awk 'NR==5{exit}1' | tac
    5
    6
    7
    8
    
    • tac 反转文件。
    • awk 打印前 4 行并退出(如果您的文件非常大,最好使用)
    • tac 再次反转文件

    【讨论】:

    • 从技术上讲,您仍在使用 awk,并与另一个我认为可以接受且有用的工具结合使用 - 更容易记住和输入。
    【解决方案7】:
    awk 'NR==5, NR==8{print NR} file
    

    从第 5 行到第 8 行打印

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-23
      • 2022-06-15
      相关资源
      最近更新 更多