I am passing command line arguments to a shell script and it is being compared aganist a regular expression. The following code is case-sensitive:
[[ $1 =~ ^(cat)|(dog)$ ]] && echo "match" || echo "no match"
How can I modify this regex that will ignore cases? I would be able to pass cAt and it should match.
I want to use /i regex flag as it ignores cases. But how do I use it inside a shell script? I have tried [[ $1 =~ /(cat)|(dog)/i ]] but the script exited with a syntax error.
StackOverflow has a similar question but it does not answer my inquiry. I want to use test to compare both strings and not interested to use shopt -s nocasematch or grep <expression>
just use
shopt -s nocasematch
before your command.
alternatively
shopt -s nocasematch && [[ 'doG' =~ (cat)|(dog) ]] && echo 'hi' || echo 'no match'
Related
I have a file (file.txt) that contains some text like:
000000000+000+0+00
000000001+000+0+00
000000002+000+0+00
and I am trying to check each line to make sure that it follows the format:
character*9, "+", character*3, "+", etc
so far I have:
#!/bin/ksh
file=file.txt
line_number=1
for line in $(cat $file)
do
if [[ "$line" != "[[.]]{9}+[[.]]{3}+[[.]]{1}+[[.]]{2} ]" ]]
then
echo "Invalid number ($line) check line $line_number"
exit 1
fi
let "line_number++"
done
however this does not evaluate correctly, no matter what I put in the lines the program terminates.
When you want line numbers of the mismatches, you can use grep -vn. Be careful with writing a correct regular expression, and you will have
grep -Evn "^.{9}[+].{3}[+].[+].{2}$" file.txt
This is not in the layout that you want, so change the layout with sed:
grep -Evn "^.{9}[+].{3}[+].[+].{2}$" file.txt |
sed -r 's/([^:]*):(.*)/Invalid number (\2) check line number \1./'
EDIT:
I changed .{1} into ..
The sed is also over the top. When you need spme explanation, you can start with echo "Linenr:Invalid line"
I'm having funny results putting the regex in the condition directly:
$ line='000000000+000+0+00'
$ [[ $line =~ ^.{9}\+.{3}\+.\+..$ ]] && echo ok
ksh: syntax error: `~(E)^.{9}\+.{3}\+.\+..$ ]] && echo ok
' unexpected
But if I save the regex in a variable:
$ re="^.{9}\+.{3}\+.\+..$"
$ [[ $line =~ $re ]] && echo ok
ok
So you can do
#!/bin/ksh
file=file.txt
line_number=1
re="^.{9}\+.{3}\+.\+..$"
while IFS= read -r line; do
if [[ ! $line =~ $re ]]; then
echo "Invalid number ($line) check line $line_number"
exit 1
fi
let "line_number++"
done < "$file"
You can also use a plain glob pattern:
if [[ $line != ?????????+???+?+?? ]]; then echo error; fi
ksh glob patterns have some regex-like syntax. If there's an optional space in there, you can handle that with the ?(sub-pattern) syntax
pattern="?????????+???+?( )?+??"
line1="000000000+000+0+00"
line2="000000000+000+ 0+00"
[[ $line1 == $pattern ]] && echo match || echo no match # => match
[[ $line2 == $pattern ]] && echo match || echo no match # => match
Read the "File Name Generation" section of the ksh man page.
Your regex looks bad - using sites like https://regex101.com/ is very helpful. From your description, I suspect it should look more like one of these;
^.{9}\+.{3}\+.{1}\+.{2}$
^[^\+]{9}\+[^\+]{3}\+[^\+]{1}\+[^\+]{2}$
^[0-9]{9}\+[0-9]{3}\+[0-9]{1}\+[0-9]{2}$
From the ksh manpage section on [[ - you would probably want to be using =~.
string =~ ere
True if string matches the pattern ~(E)ere where ere is an extended regular expression.
Note: As far as I know, ksh regex doesn't follow the normal syntax
You may have better luck with using grep:
# X="000000000+000+0+00"
# grep -qE "^[^\+]{9}\+[^\+]{3}\+[^\+]{1}\+[^\+]{2}$" <<<"${X}" && echo true
true
Or:
if grep -qE "^[^\+]{9}\+[^\+]{3}\+[^\+]{1}\+[^\+]{2}$" <<<"${line}"
then
exit 1
fi
You may also prefer to use a construct like below for handling files:
while read line; do
echo "${line}";
done < "${file}"
I am able to validate IPv6 addresses using java with following regex:
([0-9a-fA-F]{0,4}:){1,7}([0-9a-fA-F]){0,4}
But I need to do this in shell script to which I am new.
This regex doesn't seem to work in shell. Have tried some other combinations also but nothing helped.
#!/bin/bash
regex="([0-9a-fA-F]{0,4}:){1,7}([0-9a-fA-F]){0,4}"
var="$1"
if [[ "$var" =~ "$regex" ]]
then
echo "matches"
else
echo "doesn't match!"
fi
It gives output doesn't match! for 2001:0Db8:85a3:0000:0000:8a2e:0370:7334
How can I write this in shell script?
Java regex shown in question would work in bash as well but make sure to not to use quoted regex variable. If the variable or string on the right hand side of =~ operator is quoted, then it is treated as a string literal instead of regex.
I also recommend using anchors in regex. Otherwise it will print matches for invalid input as: 2001:0db8:85a3:0000:0000:8a2e:0370:7334:foo:bar:baz.
Following script should work for you:
#!/bin/bash
regex='^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$'
var="$1"
if [[ $var =~ $regex ]]; then
echo "matches"
else
echo "doesn't match!"
fi
[[ and =~ won't work with sh, and awk almost works everywhere.
Here is what I did
saved as ./check-ipv6.sh, chmod +x ./check-ipv6.sh
#!/bin/sh
regex='^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$'
echo -n "$1" | awk '$0 !~ /'"$regex"'/{print "not an ipv6=>"$0;exit 1}'
Or you prefer bash than sh
#!/bin/bash
regex='^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$'
awk '$0 !~ /'"$regex"'/{print "not an ipv6=>"$0;exit 1}' <<< "$1"
Test
~$ ./check-ipv6.sh 2001:0Db8:85a3:0000:0000:8a2e:0370:7334x
not an ipv6=>2001:0Db8:85a3:0000:0000:8a2e:0370:7334x
~$ echo $?
1
~$ ./check-ipv6.sh 2001:0Db8:85a3:0000:0000:8a2e:0370:7334
~$ echo $?
0
I have a value in a variable that may be absolute or relative url, and I need to check which one it is.
I have found that there's a =~ operator in [[, but I can't get it to work. What am I doing wrong?
url="http://test"
if [[ "$url" =~ "^http://" ]];
then echo "absolute.";
fi;
You need to use regex without quote:
url="http://test"
if [[ "$url" =~ ^http:// ]]; then
echo "absolute."
fi
This outputs `absolute. as regex needs to be without quote in newer BASH (after BASH v3.1)
Or avoid regex and use glob matching:
if [[ "$url" == "http://"* ]]; then
echo "absolute."
fi
I am using bash 4.1.10(4)-release and I trying to use a regex to match against two capital letters [A-Z]{2} and then anything. So for example BXCustomerAddress, CAmaterial would be acceptable, but WarehouseMessage would not. I have the following script for testing purposes:
#!/bin/bash
if [[ "Ce" =~ [A-Z]{2} ]]; then
echo "match"
fi
My questions are:
When I run this script, why does it return that I have a match?
Does anyone know how I could achieve my desired results?
Looks like you have shopt nocaseglob turned on. Turn it off using:
shopt -u nocaseglob
Now [[ "Ce" =~ [A-Z]{2} ]] should not match and will return false.
Check the value of the shell option nocasematch:
$ shopt nocasematch
nocasematch off
shopt nocasematch is probably set to on. Turn it off with
shopt -u nocasematch
From the Bash Reference Manual:
nocasematch
If set, Bash matches patterns in a case-insensitive fashion when
performing matching while executing case or [[ conditional commands.
After trying out many different combinations, this is what gave me the expected behavior:
#!/bin/bash
# [A-Z][A-Z] will not work
# [:upper:][:upper:] will not work
# [[A-Z]][[A-Z]] will not work
# [[:upper:]][[:upper:]] does work
echo "test one"
if [[ "CA" =~ ^([[:upper:]][[:upper:]])+ ]]; then
echo "match"
fi
echo "test two"
if [[ "Ce" =~ ^([[:upper:]][[:upper:]])+ ]]; then
echo "match"
fi
I get the expected results of:
test one
match
test two
Thanks for everyone's help
The code is like this:
#!/bin/bash
if [[ foobarbletch =~ 'foo(bar)bl(.*)' ]]
then
echo "The regex matches!"
echo $BASH_REMATCH
echo ${BASH_REMATCH[1]}
echo ${BASH_REMATCH[2]}
fi
When I try to run it, it doesn't display anything:
bash-3.2$ bash --version
GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin12)
Copyright (C) 2007 Free Software Foundation, Inc.
bash-3.2$ /bin/bash test_rematch.bash
bash-3.2$
Does anyone have ideas about this?
In your bash REGEX, you should remove quotes. That's why that doesn't work.
If you have space, I recommend to use this way :
#!/bin/bash
x='foo bar bletch'
if [[ $x =~ foo[[:space:]](bar)[[:space:]]bl(.*) ]]
then
echo The regex matches!
echo $BASH_REMATCH
echo ${BASH_REMATCH[1]}
echo ${BASH_REMATCH[2]}
fi
You can also assign the quoted regexp to a variable:
#!/bin/bash
x='foobarbletch'
foobar_re='foo(bar)bl(.*)'
if [[ $x =~ $foobar_re ]] ; then
echo The regex matches!
echo ${BASH_REMATCH[*]}
echo ${BASH_REMATCH[1]}
echo ${BASH_REMATCH[2]}
fi
This not only supports simple quoting but gives the regexp a name which can help readability.
Thanks to your debugging statement, echo The regex matches!, you should have noticed there is no problem with BASH_REMATCH, since the if statement evaluates to false.
In bash, regular expressions used with =~ are unquoted. If the string on the right is quoted, then it is treated as a string literal.
If you want to include whitespaces in your regex's, then use the appropriate character classes, or escape your space if you want a space.