LinuxQuestions.org
Visit Jeremy's Blog.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 08-26-2020, 12:03 AM   #1
blason
Member
 
Registered: Feb 2016
Posts: 122

Rep: Reputation: Disabled
RegEx is not matching


Hi there,

Can someone please help me on regex pattern matching with my below function?

This is matching IPv4 addresses but somehow my IPv6 addresses are not getting matched

Code:
212.129.46.32
213.163.64.208
217.61.0.97
223.5.5.5
223.6.6.6
2001:1398:1:0:200:1:123:46
2001:19f0:5:6012:5400:2ff:fe60:7579
2001:19f0:5801:b7c::1
2001:19f0:6401:b3d:5400:2ff:fe5a:fb9f
Code:
function convert {
    while read ip; do
        if ! [[ "$ip" =~ [^0-9.-] ]];
        then
                                todo[$y]+=" $ip $ip"
                                        if [ $z -eq 2000 ]
                                        then
                                                z=0
                                                let y=$y+1
                                        else
                                                let z=$z+1
                                        fi
        fi
     done

        dynamic_objects -do ti_$type
        dynamic_objects -n ti_$type

        for i in "${todo[@]}" ;
        do
                dynamic_objects -o ti_$type -r $i -a
        done
}
 
Old 08-26-2020, 12:12 AM   #2
blason
Member
 
Registered: Feb 2016
Posts: 122

Original Poster
Rep: Reputation: Disabled
So I removed the caret which negates but this is still not working. Am I doing anything wrong with RegEx

if ! [[ "$ip" =~ [^0-9.-] ]];
 
Old 08-26-2020, 12:40 AM   #3
astrogeek
Moderator
 
Registered: Oct 2008
Distribution: Slackware [64]-X.{0|1|2|37|-current} ::12<=X<=15, FreeBSD_12{.0|.1}
Posts: 6,278
Blog Entries: 24

Rep: Reputation: 4225Reputation: 4225Reputation: 4225Reputation: 4225Reputation: 4225Reputation: 4225Reputation: 4225Reputation: 4225Reputation: 4225Reputation: 4225Reputation: 4225
Your ipv6 addresses contain characters not covered by your regex - hexadecimal digits and the colon separator.

Add those to your regex and it will work such as it is.

Of course, it will also match many things other than IP addresses as well and will not differentiate ipv4 from ipv6, but those are not mentioned as considerations so may not be important to you.

It is probably important that you at least consider a few patterns you do not want to match in order to help specify your regex more precisely. For example, your existing regex will also match phone numbers in almost any format, and with the addition of hex digits it will match many other things including "deadbeef" and 1-800-bad-deed, among a great many other things!

Last edited by astrogeek; 08-26-2020 at 01:02 AM.
 
1 members found this post helpful.
Old 08-26-2020, 01:46 AM   #4
syg00
LQ Veteran
 
Registered: Aug 2003
Location: Australia
Distribution: Lots ...
Posts: 21,161

Rep: Reputation: 4125Reputation: 4125Reputation: 4125Reputation: 4125Reputation: 4125Reputation: 4125Reputation: 4125Reputation: 4125Reputation: 4125Reputation: 4125Reputation: 4125
Ah the joys of corner cases ...

I must admit I've never had the temerity to use double negatives with regex. Life has enough angst as it is.
 
Old 08-26-2020, 02:15 AM   #5
MadeInGermany
Senior Member
 
Registered: Dec 2011
Location: Simplicity
Posts: 2,844

Rep: Reputation: 1222Reputation: 1222Reputation: 1222Reputation: 1222Reputation: 1222Reputation: 1222Reputation: 1222Reputation: 1222Reputation: 1222
Put all allowed characters into the [char set]
Code:
if [[ "$ip" !~ [^0-9a-fA-F:.] ]]
A more precise match
Code:
if [[ ".$ip" =~ ^([.][0-9]{1,3}){4}$ ]] || [[ ":$ip" =~ ^(:[0-9a-fA-F]{,4}){4,8}$ ]]
 
Old 08-26-2020, 02:27 AM   #6
blason
Member
 
Registered: Feb 2016
Posts: 122

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by MadeInGermany View Post
Put all allowed characters into the [char set]
Code:
if [[ "$ip" !~ [^0-9a-fA-F:.] ]]
A more precise match
Code:
if [[ ".$ip" =~ ^([.][0-9]{1,3}){4}$ ]] || [[ ":$ip" =~ ^(:[0-9a-fA-F]{,4}){4,8}$ ]]

Let me try that..
 
Old 08-26-2020, 02:35 AM   #7
blason
Member
 
Registered: Feb 2016
Posts: 122

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by MadeInGermany View Post
Put all allowed characters into the [char set]
Code:
if [[ "$ip" !~ [^0-9a-fA-F:.] ]]
A more precise match
Code:
if [[ ".$ip" =~ ^([.][0-9]{1,3}){4}$ ]] || [[ ":$ip" =~ ^(:[0-9a-fA-F]{,4}){4,8}$ ]]
any issues?

line 11: syntax error in conditional expression: unexpected token `('
line 11: syntax error near `^(['
line 11: `if [[ ".$ip" =~ ^([.][0-9]{1,3}){4}$ ]] || [[ ":$ip" =~ ^(:[0-9a-fA-F]{,4}){4,8}$ ]];'

Code:
function convert {
    while read ip; do
#        if ! [[ "$ip" =~ [^0-9.-] ]];
if [[ ".$ip" =~ ^([.][0-9]{1,3}){4}$ ]] || [[ ":$ip" =~ ^(:[0-9a-fA-F]{,4}){4,8}$ ]];
        then
                                todo[$y]+=" $ip $ip"
                                        if [ $z -eq 2000 ]
                                        then
                                                z=0
                                                let y=$y+1
                                        else
                                                let z=$z+1
                                        fi
        fi
     done

        dynamic_objects -do ti_$type
        dynamic_objects -n ti_$type

        for i in "${todo[@]}" ;
        do
                dynamic_objects -o ti_$type -r $i -a
        done
}
 
Old 08-26-2020, 06:45 AM   #8
boughtonp
Senior Member
 
Registered: Feb 2007
Location: UK
Distribution: Debian
Posts: 3,645

Rep: Reputation: 2564Reputation: 2564Reputation: 2564Reputation: 2564Reputation: 2564Reputation: 2564Reputation: 2564Reputation: 2564Reputation: 2564Reputation: 2564Reputation: 2564

When using Bash regex, predefine the patterns as variables with single-quotes around them, and then use those variables in the if statement.

Also, note that "::1" is a valid IPv6 address, which is not matched by that pattern, and I just noticed that the IPv4 pattern is requiring a "." at the start, which is just wrong.

The IPv6 pattern below may or not be good enough for your needs (I don't see any mention of what those are).
Likewise, IPv4 only allows each octet to be up to 255 - you may or not need separate validation to check that.

Code:
IPv4='^[0-9]{1,3}(\.[0-9]{1,3}){3}$'
IPv6='^[0-9A-Fa-f:]{3,39}$'
if [[ "$ip" =~ $IPv4 || "$ip" =~ $IPv6 ]]
then
...
fi
 
1 members found this post helpful.
Old 08-26-2020, 06:58 AM   #9
syg00
LQ Veteran
 
Registered: Aug 2003
Location: Australia
Distribution: Lots ...
Posts: 21,161

Rep: Reputation: 4125Reputation: 4125Reputation: 4125Reputation: 4125Reputation: 4125Reputation: 4125Reputation: 4125Reputation: 4125Reputation: 4125Reputation: 4125Reputation: 4125
Quote:
Almost only counts in horseshoes and hand grenades.
Certainly not regex. Precision, as in exact specification, is absolute. The more you use it, the more you see the truth in this. You can only learn it by doing.
 
Old 08-26-2020, 07:23 AM   #10
MadeInGermany
Senior Member
 
Registered: Dec 2011
Location: Simplicity
Posts: 2,844

Rep: Reputation: 1222Reputation: 1222Reputation: 1222Reputation: 1222Reputation: 1222Reputation: 1222Reputation: 1222Reputation: 1222Reputation: 1222
Corrections:
1. the !~ operator might be unknown
Code:
if ! [[ "$ip" =~ [^0-9a-fA-F:.] ]]
2. a {,4} might be interpretet as {1,4}
Code:
if [[ ".$ip" =~ ^([.][0-9]{1,3}){4}$ ]] || [[ ":$ip" =~ ^(:[0-9a-fA-F]{0,4}){4,8}$ ]]
@boughtonp, note the prepended "." or ":"

Quote:
line 11: syntax error in conditional expression: unexpected token `('
line 11: syntax error near `^(['
line 11: `if [[ ".$ip" =~ ^([.][0-9]{1,3}){4}$ ]] || [[ ":$ip" =~ ^(:[0-9a-fA-F]{,4}){4,8}$ ]];'
Ensure the executing shell is bash or zsh! E.g. at the very beginning of the script have the shebang
Code:
#!/bin/bash
 
Old 08-26-2020, 07:30 AM   #11
blason
Member
 
Registered: Feb 2016
Posts: 122

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by boughtonp View Post
When using Bash regex, predefine the patterns as variables with single-quotes around them, and then use those variables in the if statement.

Also, note that "::1" is a valid IPv6 address, which is not matched by that pattern, and I just noticed that the IPv4 pattern is requiring a "." at the start, which is just wrong.

The IPv6 pattern below may or not be good enough for your needs (I don't see any mention of what those are).
Likewise, IPv4 only allows each octet to be up to 255 - you may or not need separate validation to check that.

Code:
IPv4='^[0-9]{1,3}(\.[0-9]{1,3}){3}$'
IPv6='^[0-9A-Fa-f:]{3,39}$'
if [[ "$ip" =~ $IPv4 || "$ip" =~ $IPv6 ]]
then
...
fi
Yep that seems to have worked!! Thanks for the help
I am testing it further let me see. Hopefully should not encounter any other issues.
 
Old 08-26-2020, 08:56 AM   #12
valeoak
Member
 
Registered: Apr 2020
Location: United Kingdom
Distribution: Debian Sid, Pop!_OS
Posts: 49

Rep: Reputation: Disabled
You may find Debuggex useful for testing regex and visualising the pattern matching. They also provide some handy cheatsheets.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Find/grep command to find matching files, print filename, then print matching content stefanlasiewski Programming 9 06-30-2016 05:30 PM
[SOLVED] differences between shell regex and php regex and perl regex and javascript and mysql golden_boy615 Linux - General 2 04-19-2011 01:10 AM
[SOLVED] Perl regex not matching across multiple lines despite ms flags gfarrell Programming 30 08-18-2010 04:10 AM
Perl Script needed to be reversed to output matching, not non-matching 0bfuscated Programming 2 07-20-2010 10:51 AM
bash: better way to delete files not matching a regex? pbhj Programming 8 10-15-2007 03:05 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 04:49 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration