Regular expressions in a Bash case statement
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 ?
Bash case does not use regular expressions, but 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 :-)
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
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 [[
.
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.