unix - head AND tail of file
Solution 1
You can simply:
(head; tail) < file.txt
And if you need to uses pipes for some reason then like this:
cat file.txt | (head; tail)
Note: will print duplicated lines if number of lines in file.txt is smaller than default lines of head + default lines of tail.
Solution 2
ed
is the standard text editor
$ echo -e '1+10,$-10d\n%p' | ed -s file.txt
Solution 3
For a pure stream (e.g. output from a command), you can use 'tee' to fork the stream and send one stream to head and one to tail. This requires using either the '>( list )' feature of bash (+ /dev/fd/N):
( COMMAND | tee /dev/fd/3 | head ) 3> >( tail )
or using /dev/fd/N (or /dev/stderr) plus subshells with complicated redirection:
( ( seq 1 100 | tee /dev/fd/2 | head 1>&3 ) 2>&1 | tail ) 3>&1
( ( seq 1 100 | tee /dev/stderr | head 1>&3 ) 2>&1 | tail ) 3>&1
(Neither of these will work in csh or tcsh.)
For something with a little better control, you can use this perl command:
COMMAND | perl -e 'my $size = 10; my @buf = (); while (<>) { print if $. <= $size; push(@buf, $_); if ( @buf > $size ) { shift(@buf); } } print "------\n"; print @buf;'
Solution 4
(sed -u 10q; echo ...; tail) < file.txt
Just another variation on the (head;tail)
theme, but avoiding the initial buffer fill issue for small files.
Solution 5
It took make a lot of time to end-up with this solution which, seems to be the only one that covered all use cases (so far):
command | tee full.log | stdbuf -i0 -o0 -e0 awk -v offset=${MAX_LINES:-200} \
'{
if (NR <= offset) print;
else {
a[NR] = $0;
delete a[NR-offset];
printf "." > "/dev/stderr"
}
}
END {
print "" > "/dev/stderr";
for(i=NR-offset+1 > offset ? NR-offset+1: offset+1 ;i<=NR;i++)
{ print a[i]}
}'
Feature list:
- live output for head (obviously that for tail is not possible)
- no use of external files
- progressbar one dot for each line after the MAX_LINES, very useful for long running tasks.
- progressbar on stderr, assuring that the progress dots are separated from the head+tail (very handy if you want to pipe stdout)
- avoids possible incorrect logging order due to buffering (stdbuf)
- avoid duplicating output when total number of lines is smaller than head + tail.
toop
Updated on July 10, 2022Comments
-
toop almost 2 years
Say you have a txt file, what is the command to view the top 10 lines and bottom 10 lines of file simultaneously?
i.e. if the file is 200 lines long, then view lines 1-10 and 190-200 in one go.
-
cnicutar over 12 yearsWhat do you mean "in one go" ?
-
toop over 12 years@cnicutar ie. not going head -10 file looking at the data and then separately going tail -10 file and looking at the data
-
sorin almost 7 years@toop If you want a real working example, see stackoverflow.com/a/44849814/99834
-
-
Paul over 12 yearsWhat if the file has more or less than 200 lines? And you don't know the number of lines ab initio?
-
Paul over 12 yearsNice, I have always used
cat
andhead
ortail
piped, good to know that I can use them individually! -
toop over 12 yearsHow can I then pipe these first 10+last 10 into another command?
-
Paul over 12 years
head file.txt; tail file.txt | your_program
-
toop over 12 years@Paul - with 'your_program' as wc -l it returns 10 instead of 20
-
Paul over 12 years
(head .vimrc ; tail .vimrc) | wc -l
-
kev over 12 years@Paul I've changed
sed
toed
-
Samus_ over 12 yearsit needs more work in order to avoid issues when offset is larger than the file
-
jstarek over 12 yearsWhy use cat when you can just call head -10 file.txt?
-
glenn jackman over 12 yearsor, without having to spawn a subshell:
{ head file; tail file; } | prog
(spacing inside the braces, and the trailing semicolon are required) -
chepner about 12 yearsStrictly speaking, this doesn't give you the tail of the original file, but the tail of the stream after
head
has consumed the first 10 lines of the file. (Compare this withhead < file.txt; tail < file.txt
on a file with fewer than 20 lines). Just a very minor point to keep in mind. (But still +1.) -
Simon Hibbs almost 12 yearsNice. If you want a gap between the head and tail parts: (head;echo;tail) < file.txt
-
ricardo almost 12 yearsCan you make the number of lines variable, so the call is something like: head_ tail(foo, m,n) - returning the first m snd last n lines of text?
-
Paul almost 12 years@ricardo that would involve writing a bash script that takes 3 args and passes them to
tail
andhead
or a function by alias-ing it. -
Kevin over 11 yearsThis works for files of known length, but not files whose length is unknown.
-
zellyn over 11 yearsCurious about why/how this works. Asked it as a new question: stackoverflow.com/questions/13718242
-
Camille Goudeseune about 11 yearsYay, this works with piped output, not just files:
a.out | awk -v ...
-
Samus_ about 11 yearsindeed :) but that's awk's normal behavior, most commandline programs work on stdin when invoked without arguments.
-
mah over 10 yearsWow... a down-vote for having an answer quite similar to others (yet timestamped before them) after almost two years, from someone who chose not to post why they down-voted. Nice!
-
jfs over 10 years+1 for stream support. You could reuse stderr:
COMMAND | { tee >(head >&2) | tail; } |& other_commands
-
jfs over 10 years@chepner:
{ tee >(head >&2) | tail; } 2>&1 < file.txt
instead of{ head; tail; } < file.txt
supports overlapping lines if you need it.{}
instead of()
are to avoid creating a subshell. -
jfs over 10 yearsbtw, it breaks for files larger than the buffer size (8K on my system).
cat >/dev/null
fixes it:COMMAND | { tee >(head >&2; cat >/dev/null) | tail; } |& other_commands
-
fedorqui over 9 yearsWould be best to post the relevant parts of the code.
-
nametal over 8 yearsaddition to @chepner 's comment:
(head;less) < file.txt
will show the remaining lines (line 11+) afterhead
-
chepner over 8 years@nametal Actually, you might not even get that much. While
head
only displays the first 10 lines of its input, there is no guaranteed that it didn't consume more of it in order to find the 10th line ending, leaving less of the input forless
to display. -
modular over 7 yearsSorry to say, but the answer only works in some cases.
seq 100 | (head; tail)
gives me only first 10 numbers. Only on much larger input size (likeseq 2000
) the tail gets some input. -
where23 about 7 yearsI use it to check time from log file.
(head -n1; tail -n1) < file.txt
-
plhn about 7 yearsMaybe this is possible :
cat file.txt | (head; tail)
-
Josiah Yoder about 7 years@alkar @J.F.Sebastian
seq 100 | { tee >(head >&2) | tail; } 2>&1;
also works to avoid the problem that we don't know how much head consumes from the stream -
sorin almost 7 yearsVery close to the desired behaviour but it seems that for <10 lines it does add extra new lines.
-
sorin almost 7 yearsIf you want to avoid duplication of lines see stackoverflow.com/a/44849814/99834
-
Alexej Magura almost 7 years@chepner I get the first and last line with
(head -n1; tail -1)
:cat FILE | (head -n1; tail -1)
. What system are you running these on/are these the GNU versions of the above commands? -
Alexej Magura almost 7 years@chepner Note: I still get the actual first and last line even with
(head; tail) < FILE
. I'm using GNU coreutils version 8.4 -
bennythejudge over 5 yearsthis is not working for me on a 89 lines text file on macos and I have tried both the native
head
/tail
and alsoghead
andgtail
. Onlyhead
is printing some text. -
Jan over 4 yearsI loved the solution, but after playing for a a while I noticed that in some cases the tail was running before the head ... there are no guaranteed ordering between
head
andtail
commands :\ ... -
haui over 4 yearsNote: The buffering issue (head swallows to much from the input stream on small files so that no tail is printed) is fixed by an answer below:
cat file.txt | (sed -u 10q ; echo ; tail)
-
Mat M about 3 yearsBasically, it uses collections.deque to simulate tail
-
jamesbtate almost 3 yearsThis is the best answer here. I added it to my
.bashrc
in a function so I can just pipe toheadtail
. -
Admin about 2 yearsAs it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.
-
steveb about 2 yearsThis solution seems to sometimes work and sometimes not. So far the
sed -u
solution mentioned in the comments here and in one of the answers, appears to work for me.