Awk - 打印文件的最后4行

3

我有一个测试文件:

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:

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

3
你是不是为文件的每一行分别派生了一个 wc?像你这样的人才是导致出现配置 4GHz 八核CPU和64GB内存的原因 :) - Jens
哦,它不起作用是因为system()返回一个退出状态(在这种情况下为0 -> 总是真),而不是wc的输出。正如你所看到的那样,每行都会打印stdout(“8”)。 - Jens
谢谢您的澄清,但我仍然不知道如何改进命令系统()。 - Tedee12345
9个回答

14
不需要使用awk,用tail即可:
$ tail -4 your_file

2
谢谢,回答很好,但问题是关于awk和最后一个命令的。 - Tedee12345
1
为什么要复杂化,当有一个简单的解决方案存在呢? - user647772
感谢解决方案的提议。 - Tedee12345
一般情况下的实用解决方案可以是将tail命令的输出通过管道传递给awk: tail -4 file | awk '{print}' 在这里,"print"可以是一些更有用的awk表达式。 - Bengt Olsson

9

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'

但是,实际上,你为什么要这样做呢?

不错的解决方案,但适用于打印少量的行。如果我要打印更多行,命令就会变得更长。 - Tedee12345
实际上,这是一个糟糕的解决方案!但如果您使用带有for循环的第二种形式,它可以很好地扩展。即 awk '{a[++i%n]=$0} END {for(j=0;j<n;j++) print a[++i%n]}' n=256 - William Pursell
这个解决方案很好。但我会等待建议来改进我的第二个命令系统()。 - Tedee12345
你评论中提供的解决方案是正确的方法。原理类似于我在这里的回答(http://stackoverflow.com/questions/12443105/insert-text-at-the-beginning-of-each-line-from-2-to-end-5/12450513#12450513)。 - Dennis Williamson
sed is the wrong solution too for any number more than single digits : ( pvE 0.1 in0 < "${m3t}" | gsed ; ) 1.36s user 0.40s system 119% cpu 1.474 total 97 43963. 29b490a426cf249805300b3b493b048b stdin; ( pvE 0.1 in0 < "${m3t}" | awktail -n 97; ) 1.06s user 0.44s system 117% cpu 1.271 total 29b490a426cf249805300b3b493b048b stdin - RARE Kpop Manifesto
显示剩余2条评论

7

使用 GNU awk 的一种方法:

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

结果:

5
6
7
8

感谢提出解决方案的建议。 - Tedee12345
@Steve:嗯... 它使用了哪些其他awk所缺乏的“gawk”特定功能?我没有发现任何区别。 - RARE Kpop Manifesto

6

如果你只是想要一个提高在 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,因为在BEGIN块内FILENAME未定义。 请注意,这两种方法都没有从awk内部使用system,因为没有很好的方法来获取system的输出,但您可以做一些丑陋的事情,比如:

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

我不能强调这只是一种学术练习。请不要使用awk!

感谢提供解决方案的建议。 - Tedee12345
@WilliamPursell: 对于“tail”,核心实用程序可能有轻微的优势。对于“head”,“gnu-head”的损失相当大:(pvE 0.1 in0 < $ {m3t} | mawk2 '+ __<NR{exit}__' FS ='^ $' __=10000000;)1.25秒用户0.48秒系统118%CPU 1.463总计721d7f270ce3eba05e57ec5e3a021675 stdin;(pvE 0.1 in0 < $ {m3t} | ghead -n 10000000;)1.46秒用户1.14秒系统122%CPU 2.118总计721d7f270ce3eba05e57ec5e3a021675 stdin - RARE Kpop Manifesto

4

这里是另一种使用 tacawk 的方法:

$ tac file | awk 'NR==5{exit}1' | tac
5
6
7
8
  • 使用tac命令来倒序显示文件。
  • 使用awk命令打印前四行并退出(如果您的文件非常大,则使用此命令很好)。
  • 再次使用tac命令来倒序显示文件。

从技术上讲,您仍在使用awk,与我发现可接受和有用的另一种工具结合使用 - 更容易记住和输入。 - Tony Barganski

4

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

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

1
awk 'NR==5, NR==8{print NR} file

打印从第5行到第8行的内容


0

这个使用 awk 的解决方案更加逐字逐句,但通过使用环形缓冲区避免了字符串操作。

它可以作为一行代码运行,但我对其进行了格式化以提高可读性。在开始块中用数字替换 l,即可指定所需的行数。

awk 'BEGIN {
         l=4; i=0
     }
     {
         b[i]=$0;
         i=(i+1)%l
     }
     END {
         for(j=i; j < l; j++)
         {
             print b[j]
         } 
         for(j=0; j < i; j++)
         {
             print b[j]
         }
     }'

0

除非你的文件比2GB大得多,否则对于这个1.85GB的测试文件,1.84秒应该已经足够快了,无需不断更新数组中的同4个单元格:

( time ( pvE0 < "${m3t}" | 

 {m,g}awk 'BEGIN {  __ = _ += _+= _^= FS = OFS = ORS 
                    RS = "^$"
                     _ = "\17\24\31"
                ORS = ___
           } NF<__ || sub("^",_,$(NF-__))+sub(("^.+")_,___)' ) | 

pvE9 ) | wc5 | lgp3


      in0: 1.85GiB 0:00:00 [3.08GiB/s] [3.08GiB/s] [========>] 100%            
     out9: 5.86KiB 0:00:01 [3.22KiB/s] [3.22KiB/s] [ <=> ]
( pvE 0.1 in0 < "${m3t}" | mawk2 ; ) 


0.73s user 1.12s system 100% cpu 1.843 total

rows       = 4. | UTF8 chars = 2167. | bytes      = 6005.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接