Count total number of lines before/after a pattern match
Number of lines before and after a match, including the match (i.e. you need to subtract 1 from the result if you want to exclude the match):
sed -n '0,/pattern/p' file | wc -l
sed -n '/pattern/,$p' file | wc -l
But this has nothing to do with IP addresses in particular.
Maybe the easiest is,
sed -n '/pattern/{=; q;}' file
Thanks @JoshepR for pointing the error
I did this two ways, though I think I like this best:
: $(( afterl=( lastl=$(wc -l <~/file) ) - 2 -
$(( beforel=( matchl=$(sed -n "/$IP/{=;q;}" <~/file) ) - 1
)) ))
for n in last match afters befores
do printf '%s line%s :\t%d\n' \
"${n%s}" "${n##*[!s]}" $((${n%s}l))
done
That saves all of those as current shell variables - and evaluates them in the for loop afterwards for output. It counts the total lines in the file with wc
and the gets the first matched line number with sed
.
Its output:
last line : 1000
match line : 200
after lines : 799
before lines : 199
I also did:
sed -n "/$IP/=;\$=" ~/file |
tr \\n \ | {
IFS=' ' read ml ll
printf '%s line%s:\t%d\n' \
last '' $((ll=${ll##* }))
match '' $ml \
after s "$((al=ll-ml-1)) \
before s $((bl=ml-1))
}
sed
prints only matching and last line numbers, then tr
translates the intervening \n
ewlines to , and read
reads the first of sed
's results into $ml
and all others into $ll
. Possible multiple match cases are handled by stripping all but the last result out of $ll
's expansion when setting it again later.
Its output:
last line : 1000
match line : 200
after lines : 799
before lines : 199
Both methods were tested on the file generated in the following way:
IP='some string for which I seek'
for count in 1 2 3 4 5
do printf '%.199d%s\n' 0 "$IP"
done | tr 0 \\n >~/file
It does, by line number:
- sets the search string
- loops five times to ensure there will be multiple matches
- prints 199 zeroes then
"$IP"
then a\n
ewline - pipes output to
tr
- which translates zeroes to\n
ewlines then into~/file