用awk实现尾部

Luc*_*che 3 linux bash scripting awk tail

好吧,所以在这里,我正在努力与这个awk代码,它应该模仿tail命令

num=$1;
{
    vect[NR]=$0;

}
END{
    for(i=NR-num;i<=NR;i++)
            print vect[$i]
}
Run Code Online (Sandbox Code Playgroud)

所以我在这里尝试实现的是由awk模拟的tail命令,例如考虑cat somefile | awk -f tail.awk 10 shoud打印文本文件的最后10行,有什么建议吗?

Ada*_*atz 6

所有这些答案都存储整个源文件.这是一个可怕的想法,将打破更大的文件.

这是一种只存储要输出的行数的快速方法(请注意,效率越高,tail总是会更快,因为它不会读取整个源文件!):

awk -vt=10 '{o[NR%t]=$0}END{i=(NR<t?0:NR);do print o[++i%t];while(i%t!=NR%t)}'
Run Code Online (Sandbox Code Playgroud)

更清晰(并且代码更少):

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)
  }'
Run Code Online (Sandbox Code Playgroud)

清晰易读的代码说明:

这使用模运算符仅存储所需数量的项(tail变量).在解析每一行时,它存储在较旧的数组值之上(因此第11行存储在其中output[1]).

END节将增量变量i设置为零(如果我们的行数少于所需的行数)或者行数,它告诉我们从何处开始调用保存的行.然后我们按顺序打印保存的行.当我们返回到第一个值(在我们打印之后)时,循环结束.

您可以替换if/ elsestanza(或我的高尔夫示例中的三元子句),i = NR如果您不关心获取空行来填充请求的数字(echo "foo" |awk -vt=10 …在"foo"行之前将有九个空行).


Kev*_*vin 5

for(i=NR-num;i<=NR;i++)
    print vect[$i]
Run Code Online (Sandbox Code Playgroud)

$表示位置参数.使用简单i:

for(i=NR-num;i<=NR;i++)
    print vect[i]
Run Code Online (Sandbox Code Playgroud)

对我有用的完整代码是:

#!/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]
}
Run Code Online (Sandbox Code Playgroud)

您可能应该添加一些代码END来处理NR< num.