awk -v tail=10 '
{
output[NR % tail] = $0
}
END {
if(NR < tail) {
i = 0
} else {
i = NR
}
do {
i = (i + 1) % tail;
print output[i]
} while (i != NR % tail)
}'
#!/usr/bin/awk -f
BEGIN{
num=ARGV[1];
# Make that arg empty so awk doesn't interpret it as a file name.
ARGV[1] = "";
}
{
vect[NR]=$0;
}
END{
for(i=NR-num;i<=NR;i++)
print vect[i]
}
5条答案
按热度按时间vcirk6k61#
所有这些答案都存储了 * 整个 * 源文件。这是一个可怕的想法,会破坏更大的文件。
这里有一个只存储要输出的行数的快速方法(注意,更高效的
tail
总是更快,因为它不会读取整个源文件!):字符串
更清晰(code golf更少):
型
易读代码的解释:
这使用modulo operator来存储所需数量的元素(
tail
变量)。当每一行被解析时,它都存储在旧数组值的顶部(因此第11行存储在output[1]
中)。END
节将增量变量i
设置为零(如果我们得到的行数少于预期的行数)或行数,这告诉我们从哪里开始调用保存的行。然后我们按顺序打印保存的行。当我们返回到第一个值时(在我们打印完它之后),循环结束。如果您不关心是否需要空白行来填充请求的数字,可以将
if
/else
节(或者在我的golfed示例中的ternary clause)替换为i = NR
(echo "foo" |awk -vt=10 …
在带有“foo”的行之前有九个空白行)。7qhs6swi2#
字符串
$
表示一个位置参数。只使用普通的i
:型
对我有效的完整代码是:
型
您可能应该向
END
添加一些代码来处理NR
<num
的情况。2exbekwf3#
您需要将
-v num=10
添加到awk命令行以设置num
的值。并在最后一个循环中从NR-num+1
开始,否则您将以num+1
行输出结束。kqlmhetl4#
这可能对你有用:
字符串
00jrzges5#
tail
实际上取决于两个完全不同的场景:1.从管道进来,是的,遵循其他人提到的标准
arr[ NR % tail_n ]
方法。1.作为一个固定的文件,(或者任何“可搜索”的虚拟设备),特别是如果文件很大,并且您正在寻找的#行很大,那么在前面做一个快速的
wc -l
并跳过所有的临时数组存储是值得的:根据文件的总大小与行计数的比率,
tail
的速度是awk-tail
的1. 0倍到2. 5倍,特别是对于固定文件而不是管道。