Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I am having a long list of IP addresses, which are not in sequence. I need to find how many IP addresses are there before/after a particular IP address. How can I achieve this?

share|improve this question
    
Do you have duplicated IP? –  cuonglm Jul 24 at 15:18
    
No. All IP addresses are unique. –  Mandar Shinde Jul 24 at 15:19
    
What does before/after mean for an IP address? In particular, do you have both IPv4 and IPv6 addresses? How do they compare? –  vinc17 Jul 24 at 15:20
    
Do you need the file sorted? –  cuonglm Jul 24 at 15:21
1  
@vinc17 - File only contains IP addresses (IPv4), no other data is included. If there are 1000 IP addresses in total, and match is found at 300th location, means there are 299 lines before the match and 700 lines after the match. –  Mandar Shinde Jul 24 at 15:28

7 Answers 7

up vote 5 down vote accepted

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

share|improve this answer

Maybe the easiest is,

sed -n '/pattern/{=; q;}' file

Thanks @JoshepR for pointing the error

share|improve this answer
    
thank you. this saves me some typing. –  mikeserv Jul 24 at 15:44
    
This just prints the line number on which the pattern occurred. –  Joseph R. Jul 24 at 15:45
    
@JosephR. - no, it prints every line number on which every match occurs. –  mikeserv Jul 24 at 15:46
    
@mikeserv I know but the OP specified that IP addresses are unique. The OP also doesn't want the line number where the match(es) occurred; they want the number of lines before the pattern occurred and the number of lines after it. –  Joseph R. Jul 24 at 15:48
    
@JosephR - the quickest way to arrive at those counts is to tally the line numbers - I would just pipe this directly to dc, myself, probably. –  mikeserv Jul 24 at 15:49

Here's a little bit of Perl code that does it:

perl -ne '
     if(1 .. /192\.168\.1\.1/) { $before++ }
     else                      { $after++  }
     $before--; # The matching line was counted
     END{print "Before: $before, After: $after\n"}' your_file

This counts the total number of lines before and after the line containing the IP 192.168.1.1. Replace with your desired IP.

Using nothing but Bash:

before=0
match=0
after=0
while read line;do
    if [ "$line" = 192.168.1.1 ];then
        match=1
    elif [ $match -eq 0 ];then
        before=$(($before+1))
    else
        after=$(($after + 1))
    fi
done < your_file
printf "Before: %d, After: %d\n" "$before" "$after"
share|improve this answer
    
BASH is preferred. –  Mandar Shinde Jul 24 at 15:29
2  
@Joseph R.: Why don't you use $. instead of a counter? –  cuonglm Jul 24 at 15:31
    
@Gnouc I could of course. I just think this is more readable than setting $after to $. - $before. –  Joseph R. Jul 24 at 15:33
    
No, I mean: if matched, print $. - 1, save $. to $tmp. End print $. - $tmp. So we don't need counter for both before and after. Of course it's less readble than yours. –  cuonglm Jul 24 at 15:38
    
@MandarShinde Please see the edit. I added a pure Bash answer. –  Joseph R. Jul 24 at 15:41

I was trying the following commands, which are a bit complicated, but would give accurate results:

After:

a=$(cat file | wc -l) && b=$(cat -n file | grep <Pattern> | awk '{print $1}') && echo "$a - $b" | bc -l

Before:

echo "`cat -n file | grep <Pattern> | awk '{print $1}'`-1" | bc -l
share|improve this answer

An awk solution reporting number of lines before and after last match

awk '/192\.168\.1\.1/{x=NR};{y=NR} END{printf "before-%d, after-%d\n" , x-1, y-x}'  file
share|improve this answer

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
share|improve this answer

Grep has a feature that can count the number of times a particular pattern is found. If you use the -c command that will do so. With the -c and -v command, this will count how many times this does not match a particular pattern

Example:

grep -c -v <pattern> file

So if you try something like:

grep -c -v 192.168.x.x file.log that should work. Hope this helps.

share|improve this answer
    
This counts the number of occurrences of the target IP. This is not what the OP asked for. –  Joseph R. Jul 24 at 15:21
    
I just edited it, if he is asking to count all other IPs before and after a particular IP, the edit should work for him. –  ryekayo Jul 24 at 15:22

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.