Regular expressions in a Bash case statement
RegexBashCaseGlobRegex Problem Overview
I am using following script, which uses case statement to find the server.
#!/bin/bash
SERVER=$1;
echo $SERVER | egrep "ws-[0-9]+\.host\.com";
case $SERVER in
ws-[0-9]+\.host\.com) echo "Web Server"
;;
db-[0-9]+\.host\.com) echo "DB server"
;;
bk-[0-9]+\.host\.com) echo "Backup server"
;;
*)echo "Unknown server"
;;
esac
But it is not working. Regex is working with egrep but not with case. sample O/P
./test-back.sh ws-23.host.com
ws-23.host.com
Unknown server
Any Idea ?
Regex Solutions
Solution 1 - Regex
Bash case does not use regular expressions, but http://www.gnu.org/software/bash/manual/bashref.html#Pattern-Matching">shell pattern matching only.
Therefore, instead of regex ws-[0-9]+\.host\.com
you should use pattern ws*.host.com
(or ws-+([0-9]).host.com
, but that looks a bit advanced and I've never tried that :-)
Solution 2 - Regex
If you want assert that *
really matches digits in ws*.host.com
and want to use case
instead of if
, elif
, elif
...
you can use something like that:
case $SERVER in
ws-[0123456789][0123456789][0123456789].host.com) echo "Web Server" ;;
db-[0123456789][0123456789][0123456789].host.com) echo "DB server" ;;
bk-[0123456789][0123456789][0123456789].host.com) echo "Backup server" ;;
*) echo "Unknown server" ;;
esac
But that does not work for more than 999 servers.
If I had to make a script for this use case, I probably write something like that (because I love regexes and case syntax ;) ):
srv=`expr "$SERVER" : '^\(db\|bk\|ws\)-[0-9]\+\.host\.com$'`
echo -n "$SERVER : "
case $srv in
ws) echo "Web Server" ;;
db) echo "DB server" ;;
bk) echo "Backup server" ;;
*) echo "Unknown server !!!"
esac
Solution 3 - Regex
case
can only use globs. If you want to do regex matching then you'll need to use a series of if-then-else-elif-fi
statements, with [[
.
Solution 4 - Regex
For reference, however this is already mentioned in this answer, from man bash
Pattern Matching section provide rules for composite pattern creation as:
>Composite patterns may be formed using one or more of the following sub-patterns:
>
>?(pattern-list)
> Matches zero or one occurrence of the given patterns.
>*(pattern-list)
> Matches zero or more occurrences of the given patterns.
>+(pattern-list)
> Matches one or more occurrences of the given patterns.
>@(pattern-list)
> Matches one of the given patterns.
>!(pattern-list)
> Matches anything except one of the given patterns.
However using these extended pattern matching require extglob
shell option to be enabled.
Here is example of code for current problem:
shopt -s extglob;
SERVER="ws-45454.host.com";
case $SERVER in
ws-+([0-9])\.host\.com) echo "Web Server"
;;
db-+([0-9])\.host\.com) echo "DB server"
;;
bk-+([0-9])\.host\.com) echo "Backup server"
;;
*)echo "Unknown server"
;;
esac;
shopt -u extglob;
also, this: shopt | grep extglob
can be used to check for its default value.
Solution 5 - Regex
Here’s an example of how to use the elif construct.
#!/bin/bash
SERVER=$1;
regex_ws="^ws-[0-9]+\.host\.com$"
regex_db="^db-[0-9]+\.host\.com$"
regex_bk="^bk-[0-9]+\.host\.com$"
if [[ "${SERVER}" =~ $regex_ws ]]; then
echo "Web Server"
elif [[ "${SERVER}" =~ $regex_db ]]; then
echo "DB server"
elif [[ "${SERVER}" =~ $regex_bk ]]; then
echo "Backup server"
else
echo "Unknown server"
fi
I find it most reliable to store the regular expressions in their own variables.
Solution 6 - Regex
I know this is a rather old question and my solution isn't much different from what @syjust has already provided, but I wanted to show that you can do just about anything at the matching stage in a case/esac
statement.
$ cat case.sh && echo -e "#################\n" && bash case.sh ws-23.host.com
#!/bin/bash
SERVER=$1;
echo $SERVER | egrep "ws-[0-9]+\.host\.com";
case $SERVER in
$(awk '{a=0}/ws-[0-9]*.host.com/{a=1}a' <<<${SERVER}))echo "Web Server";;
$(awk '{a=0}/db-[0-9]*.host.com/{a=1}a' <<<${SERVER}))echo "DB Server";;
$(awk '{a=0}/bk-[0-9]*.host.com/{a=1}a' <<<${SERVER}))echo "Backup Server";;
*)echo "Unknown server";;
esac
#################
ws-23.host.com
Web Server
Solution 7 - Regex
You can also use expr
to do the matching; it provides a grep-like regular expression syntax that should be robust enough for this application.
#!/bin/bash
server=$1
if expr "$server" : 'ws-[0-9]\+\.host\.com' >/dev/null; then echo "Web server"
elif expr "$server" : 'db-[0-9]\+\.host\.com' >/dev/null; then echo "DB server"
elif expr "$server" : 'bk-[0-9]\+\.host\.com' >/dev/null; then echo "Backup server"
else echo "Unknown server"
fi