开发者

Grep penultimate line

开发者 https://www.devze.com 2023-04-10 21:24 出处:网络
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?

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 lin开发者_运维百科e.

Thanks


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.)


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).


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


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
0

精彩评论

暂无评论...
验证码 换一张
取 消