Implement tail with awk

牧云@^-^@ 提交于 2019-12-01 23:29:40

问题


Alright so here i am struggling with this awk code wich should emulate the tail command

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

}
END{
    for(i=NR-num;i<=NR;i++)
            print vect[$i]
}

So what i'm trying to achieve here is an tail command emulated by awk for example consider cat somefile | awk -f tail.awk 10 shoud print the last 10 lines of a text file,any suggestions ?


回答1:


for(i=NR-num;i<=NR;i++)
    print vect[$i]

$ indicates a positional parameter. Use just plain i:

for(i=NR-num;i<=NR;i++)
    print vect[i]

The full code that worked for me is:

#!/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]
}

You should probably add some code to the END to handle the case when NR < num.




回答2:


All of these answers store the entire source file. That's a horrible idea and will break on larger files.

Here's a quick way to store only the number of lines to be outputted (note that the more efficient tail will always be faster because it doesn't read the entire source file!):

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

more legibly (and with less code golf):

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)
  }'

Explanation of legible code:

This uses the modulo operator to store only the desired number of items (the tail variable). As each line is parsed, it is stored on top of older array values (so line 11 gets stored in output[1]).

The END stanza sets an increment variable i to either zero (if we've got fewer than the desired number of lines) or else the number of lines, which tells us where to start recalling the saved lines. Then we print the saved lines in order. The loop ends when we've returned to that first value (after we've printed it).

You can replace the if/else stanza (or the ternary clause in my golfed example) with just i = NR if you don't care about getting blank lines to fill the requested number (echo "foo" |awk -vt=10 … would have nine blank lines before the line with "foo").




回答3:


You need to add -v num=10 to the awk commandline to set the value of num. And start at NR-num+1 in your final loop, otherwise you'll end up with num+1 lines of output.




回答4:


This might work for you:

awk '{a=a b $0;b=RS;if(NR<=v)next;a=substr(a,index(a,RS)+1)}END{print a}' v=10


来源:https://stackoverflow.com/questions/9101296/implement-tail-with-awk

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!