从多个文件中获取最后两行

时间:2019-03-13 18:35:10

标签: awk

我可以使用tail这样的命令来获取多个文件的最后2行

$ tail -n 2 file1.txt file2.txt
==> file1.txt <==
3,2,1,1
8,8,4,4

==> file2.txt <==
B1 987 6545
C1 876 5434
$

但是我需要格式化上面的输出以使其像下面一样

3,2,1,1 file1.txt
8,8,4,4 file1.txt
B1 987 6545 file2.txt
C1 876 5434 file2.txt

有没有办法仅使用awk获得以上输出?

我尝试了以下类似操作,但仅适用于最后一行。

$ awk ' { if(FNR==1 && NR!=1)  print p,f; p=$0;f=FILENAME }  END { print p,f } ' file1.txt file2.txt
8,8,4,4 file1.txt
C1 876 5434 file2.txt
$

如何将其扩展为最后两行或n行?

3 个答案:

答案 0 :(得分:3)

使用GNU awk作为ENDFILE:

$ awk '{p2=p1; p1=$0} ENDFILE{print p2, FILENAME ORS p1, FILENAME }' file1 file2
3,2,1,1 file1
8,8,4,4 file1
B1 987 6545 file2
C1 876 5434 file2

通常对于任何数量的n行:

$ awk -v n=2 '{p[NR%n]=$0} ENDFILE{for (i=1; i<=n; i++) print p[(NR+i)%n], FILENAME}' file1 file2
3,2,1,1 file1
8,8,4,4 file1
B1 987 6545 file2
C1 876 5434 file2

在打印后添加delete p和/或执行任何您想处理的行少于n的文件。

答案 1 :(得分:1)

这不是最漂亮的解决方案,但它是awk一线请求:

awk '{if (FNR==1 && NR!=1) {print secondLast" "prevFname ORS last" "prevFname} prevFname=FILENAME;last=$0} {secondLast=prevLine;prevLine=$0} END {print secondLast" "FILENAME ORS last" "FILENAME}' file1.txt file2.txt

请注意,随着所需行数的增加,这将变得笨拙。

答案 2 :(得分:1)

以下答案代表了可与任何awk兼容的 POSIX兼容解决方案。从Ed Morton's solution中可以看出,GNU awk可以使生活变得更轻松。


最后两行:最简单的两行如下:

awk '(FNR==1) && f!="" { print t1,f; print t2,f }
     (FNR==1) { f=FILENAME }
     { t1=t2; t2=$0 }
     END { print t1, f; print t2, f}' file1 file2 file3 ...

程序引入了变量f,该变量存储文件名以及代表文件最后两行的t1t2。每次我们输入一个新的非空文件(FNR==1)或在程序末尾时,我们都使用这些变量进行打印。

但是,此方法有一个主要缺陷:

  

单行文件会产生错误结果

最后n行::如果要将其扩展到最后n行,则必须使用数组t 。此外,如果要处理少于n行的文件,则必须跟踪文件有多少行(fnr)。在程序周期开始时,后一个变量fnr将始终等于上一行的FNR

如果您要使用交换原理,也会变得有些混乱

awk -v n=2 '(FNR==1) && f!="" { for(i=1; i <= (fnr < n ? fnr : n); ++i) print t[i],f }
            (FNR==1) { f=FILENAME }
            { fnr = FNR }
            (fnr <= n) { t[fnr] = $0 }                
            (fnr >  n) { for(i=1; i < n; ++i) t[i] = t[i+1]; t[n]=$0 }
            END { for(i=1; i <= (fnr < n ? fnr : n); ++i) print t[i],f }
           ' file1 file2 file3 ...

如果要摆脱交换并使用模数计算(cfr Ed Morton),可以稍微清理一下:

awk -v n=2 'function tail { 
               for(i=1+(fnr < n ? n-fnr : 0); i<=n; ++i) print t[(fnr+i)%n],f  
            }
            (FNR==1) && f!="" { tail() }
            (FNR==1) { f=FILENAME }
            { fnr = FNR; t[FNR%n] = $0 }
            END { tail() }
           ' file1 file2 file3 ...

其中,在GNU awk中只是:

awk -v n=2 '{ t[FNR%n] = $0 }
            ENDFILE { 
              for(i=1+(FNR < n ? n-FNR : 0); i<=n; ++i) print t[(FNR+i)%n],FILENAME                
            }' file1 file2 file3 ...