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 \newlines 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:

  1. sets the search string
  2. loops five times to ensure there will be multiple matches
  3. prints 199 zeroes then "$IP" then a \newline
  4. pipes output to tr - which translates zeroes to \newlines then into ~/file