Difficulty searching for IP address in a file

Hi,

Below is the command I use to search for IP address in a file.

find ./ -type f \( -name "*.txt" -or -name "*.xml" \) | xargs grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b"

As an output I found three IP address and below is how they look.

#Listen 112.34.56.58:80
Listen 112.134.56.58:80 #This is an IP
Listen 112.34.55.58:80

The problem is I do not want any IP in output which begin with "#" i.e

# Listen 12.34.56.78:80

Because, in my case anything starting with a # usually means comments and should be ignored i.e not listed.
Can you please tell me how should I tweak my command not to display IPs mentioned in lines that start with "#" character?

Please note: Any "#" after the IP should be considered and grep like below:

Listen 112.134.56.58:80 #This is an IP

Thank you.

Maybe using an additional step to get just the IP address. Something like:

find ./ -type f \( -name "*.txt" -or -name "*.xml" \) | xargs grep -oE "^ *[^#].*\b([0-9]{1,3}\.){3}[0-9]{1,3}\b" | grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b"

or

find ./ -type f \( -name "*.txt" -or -name "*.xml" \) | xargs grep -oE "^ *[^#].*\b([0-9]{1,3}\.){3}[0-9]{1,3}\b" | awk '{print $NF}'

If your grep has the -P option you could use a lookahead to discard commented IPs.

Also here I added some more validation to discard illegal IP addresses (eg 192.999.1.1):

... | xargs grep  -oP '[^#]*\b\K(((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|\b)){4})'

grep -o breaks the rule "grep returns whole lines".
So combining it with other options like -v produces experimental results.
Rather than trying the experimental -P that might differ between grep versions, I would go to real perl, like

perl -lne '/^[^#]*\b((\d{1,3}[.]){3}\d{1,3})\b/ and print $1'

or

perl -lne 's/#.*//; /\b((\d{1,3}[.]){3}\d{1,3})\b/ and print $1'

The latter leads to sed, indeed you can use sed to pre-filter the lines and then pipe to grep

sed 's/#.*//' | grep -Eo '\b([0-9]{1,3}[.]){3}[0-9]{1,3}\b'

I tried all the suggestions but none of the helped.

A file has the below entries

#Listen 112.34.56.58:80
Listen 112.134.56.58:80 #This is an IP
Listen 112.34.55.58:80

Expectation is that the search should yield 2 / 3 IPs mentioned in the file. Yes, the entry which starts with the hash(#) i.e. #Listen 112.34.56.58:80 should not be display.

However, all the three entries are displayed which are listed in the file. One can create a file with these entries and test to see the problem themselves.

Can you please suggest please?

For me it works

cat file
#Listen 112.34.56.58:80
Listen 112.134.56.58:80 #This is an IP
Listen 112.34.55.58:80 
perl -lne 's/#.*//; /\b((\d{1,3}[.]){3}\d{1,3})\b/ and print $1' file
112.134.56.58
112.34.55.58
perl -lne '/^[^#]*\b((\d{1,3}[.]){3}\d{1,3})\b/ and print $1' file
112.134.56.58
112.34.55.58
sed 's/#.*//' file | grep -Eo '\b([0-9]{1,3}[.]){3}[0-9]{1,3}\b'
112.134.56.58
112.34.55.58

Could you please copy/paste your command/result?

I m trying the below command but I do not see any output even when I expect it to.

sed 's/#.*//' | find ./ -type f \( -name "*.txt" -or -name "*.xml" \) | grep -Eo '\b([0-9]{1,3}[.]){3}[0-9]{1,3}\b'

I do not wish to use perl.
Here is my OS details: Linux mycomp 3.10.0-693.17.1.el7.x86_64 #1 SMP Sun Jan 14 10:36:03 EST 2018 x86_64 x86_64 x86_64 GNU/Linux

I was anyways able to get this to work by rewriting the command as a script.

 for i in $( find ./ -type f \( -name "*.txt" -or -name "*.xml" \) );
 do
 sed 's/#.*//' "$i" | grep -Eo '\b([0-9]{1,3}[.]){3}[0-9]{1,3}\b'
 if [ $? -eq 0 ]; then
 echo "File:$i"
 fi
 done
 

find does not read from stdin, and sed needs an input (filename as argument or stdin).
Your script is okay.
If you take a while read loop and quote the variables that holds filenames, then it is even takes filenames with special characters.

find ./ -type f \( -name "*.txt" -o -name "*.xml" \) |
while IFS= read -r f
do
  if ips=$(sed 's/#.*//' "$f" | grep -Eo '\b([0-9]{1,3}[.]){3}[0-9]{1,3}\b')
  then
    echo "File:$f"
    echo "$ips"
  fi
done

The if takes the exit status from the last command i.e. the grep (0 gives true).
One could as well test the variable of being non-null.
The quotes in echo "$ips" keep the newlines in the variable, while echo $ips would print them in a row (and the shell tries to glob them, but you have ensured it does not have special glob characters).

1 Like