我正在努力处理这个应该模拟 tail 命令的 awk 代码
num=$1;
{
vect[NR]=$0;
}
END{
for(i=NR-num;i<=NR;i++)
print vect[$i]
}
所以我在这里想要实现的是由 awk/ 模拟的 tail 命令 例如考虑
cat somefile | awk -f tail.awk 10
应该打印文本文件的最后 10 行,有什么建议吗?
所有这些答案都存储整个源文件。这是一个可怕的想法,并且会破坏较大的文件。
这是一种仅存储要输出的行数的快速方法(请注意,更高效的
tail
总是会更快,因为它不会读取整个源文件!):
awk -vt=10 '{o[NR%t]=$0}END{i=(NR<t?0:NR);do print o[++i%t];while(i%t!=NR%t)}'
更清晰(并且更少的代码高尔夫):
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)
}'
清晰代码说明:
这使用 取模运算符 仅存储所需数量的项目(
tail
变量)。解析每一行时,它都存储在旧数组值的顶部(因此第 11 行存储在 output[1]
中)。
END
节将增量变量i
设置为零(如果我们的行数少于所需的行数)或行数,这告诉我们从哪里开始调用已保存的行。然后我们按顺序打印保存的行。当我们返回到第一个值时(在打印它之后),循环结束。
如果您不关心用空行来填充请求的数字(
if
将在“foo”行之前有九个空行)。else
i = NR
表示位置参数。使用普通的echo "foo" |awk -vt=10 …
for(i=NR-num;i<=NR;i++)
print vect[$i]
对我有用的完整代码是:
$
您可能应该向
i
添加一些代码来处理
for(i=NR-num;i<=NR;i++)
print vect[i]
#!/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]
}
时的情况。
您需要在 awk 命令行中添加
END
来设置 < NR
的值。并在最后一个循环中从 num
-v num=10
行输出。
这可能对你有用:
num
NR-num+1
确实取决于两种完全不同的场景:
num+1
方法。
awk '{a=a b $0;b=RS;if(NR<=v)next;a=substr(a,index(a,RS)+1)}END{print a}' v=10
操作是值得的,跳过所有临时数组存储:
tail
arr[ NR % tail_n ]
wc -l
根据文件的总大小与行数比率,
( time ( mawk2 -v ___='3.14159 %' 'BEGIN {
index(__ = ARGV[ARGC-!_],_ = "\47") &&
gsub(_,(_ "\\" _)_, __)
(_ = "LC_ALL=C gwc -l "(_ __)_) | getline
close(_)
printf("\f\f\t %d...\f\f\n",
___ = int(((_ = 100) - ___) * $1 /_)) >>("/dev/stderr")
FS = RS } ___ < NR' "$f" ) | pv ) | xxh128sum | gcat -b ;
sleep 4;
( time ( LC_ALL=C gtail -n 4654474 "$f" ) | pv ) | xxh128sum | gcat -b
out9: 1.39GiB 0:00:07 [ 193MiB/s] [ 193MiB/s] [ <=> ]
( mawk2 -v ___='3.14159 %' "$f" )
5.49s user 1.86s system 99% cpu 7.370 total
1 607efeee007a7e50cc06ce287a82e78f stdin
的 1.0x-2.5x,特别适用于固定文件而不是管道。