27

I have a script that generates some output. I want to check that output for any IP address like

159.143.23.12
134.12.178.131
124.143.12.132

if (IPs are found in <file>)
then // bunch of actions //
else // bunch of actions //

Is fgrep a good idea?

I have bash available.

4
  • use grep , egrep , awk , or sed , whatever u like
    – Ijaz Ahmad
    Commented Jul 18, 2016 at 10:30
  • Could you help with the syntax please? I mean how does it search for a random IP. How to describe the pattern? I would be looking for any IP address, not a particular address.
    – Koshur
    Commented Jul 18, 2016 at 10:31
  • 6
    Is that only IPv4 addresses in quad-decimal notation? Could they be written like 0010.0000.0000.0001? May the file otherwise contain things that look like IP addresses like version numbers (soft-1.2.1100.1.tar.gz, network specifications (10.0.0.0/24), 1.2.3.4.5)? Would you accept a solution that is positive on 333.444.555.666? Or 0377.0377.0377.0377 (a valid quad-octal IP address)? Commented Jul 18, 2016 at 10:47
  • If bash is available, then awk usually is also, so this might work for you: awk '/([0-9]{2,3}\.){3}/ {print $5 "\t" $1}' (This one-liner translates the output of host XFR list to /etc/hosts format.) Commented Nov 15, 2017 at 23:23

9 Answers 9

55

Yes , You have lot of options/tools to use. I just tried this , it works:

ifconfig | grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b"

so you can use grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b" to grep the ip addresses from your output.

3
  • 1
    Thanks. This works. Can you explain a bit? Is this a regular expression?
    – Koshur
    Commented Jul 18, 2016 at 10:39
  • 1
    Yes this is a regular expression used in bash with grep , you are just looking for three digits pattern separated by dots. you can play with by changing the numbers in {1,2} for 2 consecutive digits and so on
    – Ijaz Ahmad
    Commented Jul 18, 2016 at 10:43
  • 1
    One can also use "\b([0-9]{1,3}\.){3}[0-9]{1,3}\/[0-9][0-9]?" to find CIDRs (assuming they are valid)
    – vikas027
    Commented Sep 7, 2018 at 0:16
3

If your file is called e.g ips you can write somethinng like:

while read -r ip
    do
        if [[ $ip == "$1" ]]; then
            shift
            printf '%s\n' 'action to take if match found'
        else
            printf '%s\n' 'action to take if match not found'
        fi
    done < ips

Then you can pass the parameters as follow the the script

./myscript 159.143.23.12 134.12.178.131 124.143.12.132 124.143.12.132
2

starting my answer based on this answer:

Yes , You have lot of options/tools to use. I just tried this , it works:

ifconfig | grep -oE "\b([0-9]{1,3}.){3}[0-9]{1,3}\b" a so you can use grep -oE "\b([0-9]{1,3}.){3}[0-9]{1,3}\b" to grep the ip addresses from your output.

and converting the answer to full length IPv6, etc...:

fgrep -oE "\b([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}\b" -- file

if you want to keep the /nnn if it's there:

fgrep -oE "\b([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}(/[0-9]{1,3}){0,1}\b" -- file

and also there's the shortened version of IPv6 that includes '::'.

for more IPv6 answers you can look here: https://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses

1
  • fgrep is the old name for a variant of grep that ignores pattern matching. I'd recommend you use grep (or even egrep) instead, especially as you're clearly wanting pattern matching. Commented Jul 18, 2016 at 19:59
2

Tested in SmartOS (a variant of Solaris), hopefully should work in other *nix environments:

egrep '(([0-9]|[0-9]{2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[0-9]{2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])'

Example:

$ cat >file.txt
IP1: 192.168.1.1
IP2: 261.480.201.311
IP3: 1012.680.921.3411

$ egrep '(([0-9]|[0-9]{2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[0-9]{2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])' file.txt
IP1: 192.168.1.1

This pattern matches only valid IPv4, i.e, x.x.x.x where x range from 0-255. Should you need to extract only the matched IP, add an -o option to the above command. You could embed this command in a bash script and presumably in other shell scripts as well. And, if egrep fails, try grep -E ...

Using it in a (bash) shell script:

ip=$(egrep -o '(([0-9]|[0-9]{2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[0-9]{2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])' file.txt) echo $ip

2
  • This worked well on a CentOS 6 system, grep 2.6.3 Commented Feb 14, 2020 at 20:33
  • Working on FreeBSD v10.3 . Commented Apr 5, 2020 at 18:10
1
ip -4  addr show eth1 |  grep -oP '(?<=inet\s)\d+(\.\d+){3}'
0
0

If you have the list of IPs in a file, one per line, grep already has the convenient -f option:

$ man fgrep | grep file= -A1
       -f FILE, --file=FILE
              Obtain patterns from FILE, one per line.  The empty file contains zero patterns, and therefore matches nothing.  (-f is specified by POSIX.)

This may cause a few false positives due to strings optionally followed by another number to make it a different IP. Lots of things you can do about it, depending on your case you may or may not decide to worry.

0

I think my answer to another post is better suited here. Thanks to this post and others like it I came up with this, that looks for the correct IP format, then gets rid of all the lines that contain 256 or higher. Replace the IP with something that is non-valid to see no output instead:

echo '255.154.12.231' | grep -E '(([0-9]{1,3})\.){3}([0-9]{1,3}){1}' | grep -vE '25[6-9]|2[6-9][0-9]|[3-9][0-9][0-9]'

The first grep was probably found in this post and it checks for any numbers from 0-999 in the format X.X.X.X

The second grep removes lines with numbers 256-999, thus leaving only valid format IPs, so I thought

BUT... As pointed out by G-Man, I was in error by assuming the IP would be on its own line. Most always though, there will be a space or another divider to look for on either side of the IP. The spaces/dividers can be removed with sed or other means after the IP is found. I also added -o to the first grep:

echo ' 1234.5.5.4321 ' | grep -Eo ' (([0-9]{1,3})\.){3}([0-9]{1,3}){1} ' | grep -vE '25[6-9]|2[6-9][0-9]|[3-9][0-9][0-9]' | sed 's/ //'

echo ' 234.5.5.432 ' | grep -Eo ' (([0-9]{1,3})\.){3}([0-9]{1,3}){1} ' | grep -vE '25[6-9]|2[6-9][0-9]|[3-9][0-9][0-9]' | sed 's/ //'
echo ' 234.5.5.100 ' | grep -Eo ' (([0-9]{1,3})\.){3}([0-9]{1,3}){1} ' | grep -vE '25[6-9]|2[6-9][0-9]|[3-9][0-9][0-9]' | sed 's/ //'

The first and second will give no output, while the third does and the spaces are stripped.

1
  • Suppose I have 500 addresses, ranging from 10.0.0.1 to 10.0.1.244.  Your second grep would throw out that line because of the “500”.  (The question never said that the IP address(es) in the file, if any, would be on a line by themselves.)  On the other hand, it will accept 1234.1.1.1 and 1.1.1.1234. But aside from that, not bad. Commented Apr 5, 2018 at 5:07
0

Here is the short form

grep -oE "\b(\d{1,3}\.){3}\d{1,3}\b"

\d is for digits [0-9]

1
  • egrep/grep -E doesn't recognise the \d shorthand for digits, so whilst this is valid regex it's not appropriate here. Commented May 13, 2020 at 12:01
-1

Redirect that output to some outputFile

Simply grep it with pattern as,

grep -sE "159.143.23.12|134.12.178.131|124.143.12.132" <outputFile>
3
  • 5
    Note that . is a regular expression operator and needs escaping for it to be treated literally Commented Jul 18, 2016 at 10:49
  • 2
    Those aren't patterns, those are literals. Not a useful answer since the OP specified "any IP." Commented Nov 15, 2017 at 23:18
  • @MarkHudson the above example is probably just for brevity. Adding the remaining 4294967293 addresses is left as an exercise for the reader.
    – mwfearnley
    Commented May 5, 2021 at 12:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .