Home > other >  Print first few and last few lines of file through a pipe with "..." in the middle
Print first few and last few lines of file through a pipe with "..." in the middle

Time:12-08

Problem Description

This is my file

1
2
3
4
5
6
7
8
9
10

I would like to send the cat output of this file through a pipe and receive this

% cat file | some_command
1
2
...
9
10

Attempted solutions

Here are some solutions I've tried, with their output

% cat temp | (head -n2 && echo '...' && tail -n2)
1
2
...
% cat temp | tee >(head -n3) >(tail -n3) >/dev/null
1
2
3
8
9
10
# I don't know how to get the ...
% cat temp | sed -e 1b -e '$!d'
1
10

% cat temp | awk 'NR==1;END{print}'
1
10
# Can only get 2 lines

CodePudding user response:

An awk:

awk -v head=2 -v tail=2 'FNR==NR && FNR<=head
FNR==NR && cnt  ==head {print "..."}
NR>FNR && FNR>(cnt-tail)' file file

Or if a single pass is important, you can use perl:

perl -0777 -lanE 'BEGIN{$head=2; $tail=2;}
END{say join("\n", @F[0..$head-1],("..."),@F[-$tail..-1]);}' file   

Or, an awk that is one pass:

awk -v head=2 -v tail=2 'FNR<=head
{lines[FNR]=$0}
END{
    print "..."
    for (i=FNR-tail 1; i<=FNR; i  ) print lines[i]
}' file

Or, nothing wrong with being a caveman direct like:

head -2 file; echo "..."; tail -2 file

Any of these prints:

1
2
...
9
10

CodePudding user response:

I suggest with bash:

(head -n 2; echo "..."; tail -n 2) < file

Output:

1
2
...
9
10

CodePudding user response:

You may consider this awk solution:

awk -v top=2 -v bot=2 'FNR == NR {  n; next} FNR <= top || FNR > n-top; FNR == top 1 {print "..."}' file{,}

1
2
...
9
10

CodePudding user response:

Assumptions:

  • as OP has stated, a solution must be able to work with stream from a pipe

One small modification to OP's 2nd entry under Attempted solutions:

# change this:

$ cat temp | tee >(head -n3) >(tail -n3) >/dev/null

# to this:

$ cat temp | tee >(head -n2; echo '...') >(tail -n3) >/dev/null
1
2
...
8
9
10

With parameterized head/tail offsets:

$ h=2 t=3
$ cat temp | tee >(head -n${h}; echo '...') >(tail -n${t}) >/dev/null
1
2
...
8
9
10

CodePudding user response:

Two single pass sed solutions:

sed '1,2b
     3c\
...
     N
     $!D'

and

sed '1,2b
     3c\
...
     $!{h;d;}
     H;g'
  • Related