Awk 从多个文件中获取最后2行

Awk 从多个文件中获取最后2行,awk,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 $ 是否有方法仅使用awk获得上述输出 我尝试了下面这样的方法,但只适用于最后一行 $ awk ' { if(FNR==1 && NR!=1) print p,f; p=$0;f=FILE

我可以使用
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
$
是否有方法仅使用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
$

如何将其扩展到最后2行或n行?

这不是最漂亮的解决方案,但它是一个
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

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

这不是最漂亮的解决方案,但它是一个
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
请注意,随着所需行数的增加,这将变得非常笨拙。

以下答案代表了一种兼容POSIX的解决方案,可用于任何awk。正如您从中看到的,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 ...
awk-vn=2'(FNR=1)和&f=“{for(i=1;i下面的答案代表了一个与POSIX兼容的解决方案,它可以与任何awk一起工作。正如您从中看到的,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 ...

awk-vn=2'(FNR==1)和&f!='{for(i=1;i用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

$awk-vn=2'{p[NR%n]=$0}ENDFILE{for(i=1;i使用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

$awk-vn=2'{p[NR%n]=$0}ENDFILE{for(i=1;ican
for(i=1;i@stack01141006
function foo(){for(i=1;i是的..非常好的研究,感谢你探索了所有的变体..ENDFILE对我不起作用..我会接受你的答案..可以
for(i=1;i@stack01141006
function foo(){for(i=1;我是..非常好的研究,感谢您探索所有变体..ENDFILE对我不起作用..我接受您的答案..使用ENDFILE确实让生活更轻松。这应该成为POSIX的一部分。使用ENDFILE确实让生活更轻松。这应该成为POSIX的一部分。