有没有办法判断当前行是否是输入流的最后一行?
11 回答
只有在所有输入结束后,特殊END
模式才会匹配。请注意,此模式不能与任何其他模式组合。
更有用的可能是getline
伪函数,它重置$0
到下一行并返回 1,或者在 EOF 的情况下返回 0!我认为这是你想要的。
例如:
awk '{ if(getline == 0) { print "Found EOF"} }'
如果您只处理一个文件,这将是等效的:
awk 'END { print "Found EOF" }'
你有两个选择,都有点乱。
- 将每个当前行的副本存储在临时变量中,然后使用 END 块对其进行处理。
- 使用系统命令在 BEGIN 块中运行“wc -l | getline”以获取文件中的行数,然后对该值进行计数。
您可能需要稍微玩一下#2 才能让它运行,但它应该可以工作。自从我做任何awk以来已经有一段时间了。
这些是做你想做的事的唯一明智的方法,按从最好到最坏的顺序排列:
awk 'NR==FNR{max++; next} FNR == max { print "Final line:",$0 }' file file
awk -v max="$(wc -l < file)" 'FNR == max { print "Final line:",$0 }' file
awk 'BEGIN{ while ( (getline dummy < ARGV[1]) > 0) max++; close(ARGV[1])} FNR == max { print "Final line:",$0 }' file
当命令行上有多个文件时,检测 EOF 不太可靠。检测文件的开头更可靠。
为此,第一个文件是特殊的,我们忽略 FNR==1。
在第一个文件之后,FNR==1 成为前一个文件的结尾。last_filename 始终具有您正在处理的文件名。
在 else 之后进行文件处理。
在 else 块和 END 块中进行 EOF 处理。
gawk 'BEGIN{last_filename="";} \
FNR==1{if (last_filename==""){last_filename=FILENAME;} \
else {print "EOF: "last_filename;last_filename=FILENAME;}} \
END{print "END: "last_filename;}' $*
对于多个文件集,else 块在 EOF 处对除最后一个文件之外的所有文件执行。最后一个文件在 END 块中执行。
对于单个文件集,不会执行 else 块,而是执行 END 块。
gawk实现有一个特殊的规则调用ENDFILE
,它将在处理参数列表中的每个文件后触发。这有效:
awk '{line=$0} ENDFILE {print line}' files...
您可以在这里找到更多详细信息>>
我什至不确定如何对这个“解决方案”进行分类
{
t = lastline
lastline = $0
$0 = t
}
/test/ {
print "line <" $0 "> had a _test_"
}
END {
# now you have "lastline", it can't be processed with the above statements
# ...but you can work with it here
}
这个 hack 很酷的一点是,通过分配给$0
,所有剩余的声明性模式和动作都有效,一行延迟。END
即使您将其END
放在最上面,您也无法让它们为.
要检测参数列表中每个文件的最后一行,以下方法可以很好地工作:
FNR == 1 || EOF {
print "last line (" FILENAME "): " $0
}
一种简单的方法是通过中间sed
脚本运行文件,该脚本在每个非最后一行放置一个 0,在最后一行放置一个 1。
cat input_file | sed 's/^/0/;$s/0/1/' | awk '{LST=/^1/;$0=substr($0,2)}
... your awk script in which you can use LST to check for the
... last line.'
嗯 awkEND
变量告诉您何时已经到达EOF
. 我猜对你没有多大帮助
你可以试试这个:
awk 'BEGIN{PFNR=1} FNR==PFNR{PFNR++;next} {print FILENAME,PFNR=2} END{print FILENAME}' file1 file2
gawk 用户手册中提供了便携式解决方案,尽管如另一个答案中所述,gawk 本身具有 BEGINFILE 和 ENDFILE。