bashawksedheadtail

How can I read first n and last n lines from a file?


How can I read the first n lines and the last n lines of a file?

For n=2, I read online that (head -n2 && tail -n2) would work, but it doesn't.

$ cat x
1
2
3
4
5
$ cat x | (head -n2 && tail -n2)
1
2

The expected output for n=2 would be:

1
2
4
5

Solution

  • Chances are you're going to want something like:

    ... | awk -v OFS='\n' '{a[NR]=$0} END{print a[1], a[2], a[NR-1], a[NR]}'
    

    or if you need to specify a number and taking into account @Wintermute's astute observation that you don't need to buffer the whole file, something like this is what you really want:

    ... | awk -v n=2 'NR<=n{print;next} {buf[((NR-1)%n)+1]=$0}
             END{for (i=1;i<=n;i++) print buf[((NR+i-1)%n)+1]}'
    

    I think the math is correct on that - hopefully you get the idea to use a rotating buffer indexed by the NR modded by the size of the buffer and adjusted to use indices in the range 1-n instead of 0-(n-1).

    To help with comprehension of the modulus operator used in the indexing above, here is an example with intermediate print statements to show the logic as it executes:

    $ cat file   
    1
    2
    3
    4
    5
    6
    7
    8
    

    .

    $ cat tst.awk                
    BEGIN {
        print "Populating array by index ((NR-1)%n)+1:"
    }
    {
        buf[((NR-1)%n)+1] = $0
    
        printf "NR=%d, n=%d: ((NR-1 = %d) %%n = %d) +1 = %d -> buf[%d] = %s\n",
            NR, n, NR-1, (NR-1)%n, ((NR-1)%n)+1, ((NR-1)%n)+1, buf[((NR-1)%n)+1]
    
    }
    END { 
        print "\nAccessing array by index ((NR+i-1)%n)+1:"
        for (i=1;i<=n;i++) {
            printf "NR=%d, i=%d, n=%d: (((NR+i = %d) - 1 = %d) %%n = %d) +1 = %d -> buf[%d] = %s\n",
                NR, i, n, NR+i, NR+i-1, (NR+i-1)%n, ((NR+i-1)%n)+1, ((NR+i-1)%n)+1, buf[((NR+i-1)%n)+1]
        }
    }
    $ 
    $ awk -v n=3 -f tst.awk file
    Populating array by index ((NR-1)%n)+1:
    NR=1, n=3: ((NR-1 = 0) %n = 0) +1 = 1 -> buf[1] = 1
    NR=2, n=3: ((NR-1 = 1) %n = 1) +1 = 2 -> buf[2] = 2
    NR=3, n=3: ((NR-1 = 2) %n = 2) +1 = 3 -> buf[3] = 3
    NR=4, n=3: ((NR-1 = 3) %n = 0) +1 = 1 -> buf[1] = 4
    NR=5, n=3: ((NR-1 = 4) %n = 1) +1 = 2 -> buf[2] = 5
    NR=6, n=3: ((NR-1 = 5) %n = 2) +1 = 3 -> buf[3] = 6
    NR=7, n=3: ((NR-1 = 6) %n = 0) +1 = 1 -> buf[1] = 7
    NR=8, n=3: ((NR-1 = 7) %n = 1) +1 = 2 -> buf[2] = 8
    
    Accessing array by index ((NR+i-1)%n)+1:
    NR=8, i=1, n=3: (((NR+i = 9) - 1 = 8) %n = 2) +1 = 3 -> buf[3] = 6
    NR=8, i=2, n=3: (((NR+i = 10) - 1 = 9) %n = 0) +1 = 1 -> buf[1] = 7
    NR=8, i=3, n=3: (((NR+i = 11) - 1 = 10) %n = 1) +1 = 2 -> buf[2] = 8