我可以使用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行?
答案 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
,该变量存储文件名以及代表文件最后两行的t1
和t2
。每次我们输入一个新的非空文件(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 ...