ChristopherDBerry
ChristopherDBerry

Reputation: 1772

Grep penultimate line

Like the title says, how can I filter with grep (or similar bash tool) the line-before-the-last-line of a (variable length) file?

That is, show everything EXCEPT the penultimate line.

Thanks

Upvotes: 0

Views: 1922

Answers (4)

nami
nami

Reputation: 1

Using ed:

printf '%s\n' H '$-1d' wq | ed -s file          # in-place file edit
printf '%s\n' H '$-1d' ',p'  wq | ed -s file    # write to stdout

Upvotes: 0

Mat
Mat

Reputation: 206689

You can use a combination of head and tail like this for example:

$ cat input 
one
two
three
HIDDEN
four
$ head -n -2 input ; tail -n 1 input 
one
two
three
four

From the coreutils head documentation:

‘-n k’
‘--lines=k’
Output the first k lines. However, if k starts with a ‘-’, print all but the last k lines of each file. Size multiplier suffixes are the same as with the -c option.

So the head -n -2 part strips all but the last two lines of its input.

This is unfortunately not portable. (POSIX does not allow negative values in the -n parameter.)

Upvotes: 7

tripleee
tripleee

Reputation: 189357

grep is the wrong tool for this. You can wing it with something like

# Get line count
count=$(wc -l <file)
# Subtract one
penultimate=$(expr $count - 1)
# Delete that line, i.e. print all other lines.
# This doesn't modify the file, just prints
# the requested lines to standard output.
sed "${penultimate}d" file

Bash has built-in arithmetic operators which are more elegant than expr; but expr is portable to other shells.

You could also do this in pure sed but I don't want to think about it. In Perl or awk, it would be easy to print the previous line and then at EOF print the final line.

Edit: I thought about sed after all.

sed -n '$!x;1!p' file

In more detail; unless we are at the last line ($), exchange the pattern space and the hold space (remember the current line; retrieve the previous line, if any). Then, unless this is the first line, print whatever is now in the pattern space (the previous line, except when we are on the last line).

Upvotes: 2

Kent
Kent

Reputation: 195039

awk oneliner: (test with seq 10):

kent$  seq 10|awk '{a[NR]=$0}END{for(i=1;i<=NR;i++)if(i!=NR-1)print a[i]}'  
1
2
3
4
5
6
7
8
10

Upvotes: 0

Related Questions