one-liner: print all lines except the last 3?

后端 未结 10 1191
灰色年华
灰色年华 2021-01-18 01:46

I would like to simulate GNU\'s head -n -3, which prints all lines except the last 3, because head on FreeBSD doesn\'t have this feature. So I am t

相关标签:
10条回答
  • 2021-01-18 01:50

    This works with a pipe as well as an input file:

    seq 1 10 | perl -e'@x=<>;print@x[0..$#x-3]'
    
    0 讨论(0)
  • 2021-01-18 01:52
    seq 1 10 | perl -ne 'push @l, $_; print shift @l if @l > 3'
    
    0 讨论(0)
  • 2021-01-18 01:53

    Here's a late answer, because I was running into something like this yesterday.

    This solution is:

    • pure bash
    • one-liner
    • reads the input stream only once
    • reads the input stream line-by-line, not all at once

    Tested on Ubuntu, Redhat and OSX.

    $ seq 1 10 | { n=3; i=1; while IFS= read -r ln; do [ $i -gt $n ] && cat <<< "${buf[$((i%n))]}"; buf[$((i%n))]="$ln"; ((i++)); done; }
    1
    2
    3
    4
    5
    6
    7
    $ 
    

    It works by reading lines into a circular buffer implemented as an n-element array.

    n is the number of lines to cut off the end of the file.

    For every line i we read, we can echo the line i-n from the circular buffer, then store the line i in the circular buffer. Nothing is echoed until the first n lines are read. (i mod n) is the index into the array which implements the circular buffer.

    Because the requirement is for a one-liner, I tried to make it fairly brief, unfortunately at the expense of readability.

    0 讨论(0)
  • 2021-01-18 01:55
    seq 1 10 | perl -e '@x=("")x3;while(<>){print shift @x;push @x,$_}'
    

    or

    perl -e '@x=("")x3;while(<>){print shift @x;push @x,$_}' file
    

    or

    command | perl -pe 'BEGIN{@x=("")x3}push @x,$_;$_=shift @x'
    perl -pe 'BEGIN{@x=("")x3}push @x,$_;$_=shift @x' file
    
    0 讨论(0)
  • 2021-01-18 01:56

    Or do it with bash alone if you have version 4.0 or newer:

    seq 1 10 | (readarray -t LINES; printf '%s\n' "${LINES[@]:(-3)}")
    

    Update: This one would remove the last three lines instead of showing only them.

    seq 1 10 | (readarray -t L; C=${#L[@]}; printf '%s\n' "${L[@]:0:(C > 3 ? C - 3 : 0)}")
    

    For convenience it could be placed on a function:

    function exclude_last_three {
        local L C
        readarray -t L; C=${#L[@]}
        printf '%s\n' "${L[@]:0:(C > 3 ? C - 3 : 0)}"
    }
    
    seq 1 10  | exclude_last_three
    seq 11 20 | exclude_last_three
    
    0 讨论(0)
  • 2021-01-18 01:58

    This awk one-liner seems to do the job:

    awk '{a[NR%4]=$0}NR>3{print a[(NR-3)%4]}' file
    
    0 讨论(0)
提交回复
热议问题