Bash case 语句中的正则表达式

Posted

技术标签:

【中文标题】Bash case 语句中的正则表达式【英文标题】:Regular expressions in a Bash case statement 【发布时间】:2012-03-26 17:50:16 【问题描述】:

我正在使用以下脚本,它使用 case 语句来查找服务器。

    #!/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

但它不起作用。正则表达式正在与 egrep 一起使用,但不与 case 一起使用。样品O/P

./test-back.sh ws-23.host.com
ws-23.host.com
Unknown server

有什么想法吗?

【问题讨论】:

【参考方案1】:

case 只能使用 glob。如果要进行正则表达式匹配,则需要使用一系列 if-then-else-elif-fi 语句和 [[

【讨论】:

怎么样? [[ws-[0-9]+\.host\.com]]) echo "Web Server" :- 不工作 Ignacio 的意思是在级联 if ... elif ... fi 语句中使用 [[【参考方案2】:

Bash case 不使用正则表达式,而只使用shell pattern matching。

因此,您应该使用模式 ws*.host.com(或 ws-+([0-9]).host.com,但看起来有点高级,我从未尝试过 :-)

而不是正则表达式 ws-[0-9]+\.host\.com

【讨论】:

谢谢@glenn_jackman。在某些机器上(带有 bash 4.2.46(1) 的 CentOS 7.3)我收到语法错误“-bash: 语法错误接近意外标记 `('” for pattern +([a-zA-Z0-9])=*.在 fc19 bash 版本 4.2.53(1) 机器上没有语法错误 - 默认设置了 extglob。 @gaoithe 感谢您的评论!我在 case 语句中有一个 +() 构造,并且它以交互方式工作,但在 bash 脚本中语法被拒绝。直到我找到你的评论我才明白。当我在脚本中打开 extglob 时,问题就消失了。【参考方案3】:

您也可以使用expr进行匹配;它提供了一种类似于 grep 的正则表达式语法,对于这个应用程序来说应该足够健壮。

#!/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

【讨论】:

【参考方案4】:

如果您想要断言 * 确实匹配 ws*.host.com 中的数字并且想要使用 case 而不是 ifelifelif... 你可以使用类似的东西:

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

但这不适用于超过 999 台服务器。

如果我必须为这个用例编写脚本,我可能会写类似的东西(因为我喜欢正则表达式和大小写语法;)):

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 ... esac的条件也可以写成ws-[0-9][0-9][0-9].host.com)【参考方案5】:

这是一个如何使用elif 构造的示例。

#!/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

我发现将正则表达式存储在它们自己的变量中最可靠。

【讨论】:

清洁解决方案,谢谢【参考方案6】:

我知道这是一个相当古老的问题,我的解决方案与@syjust 已经提供的解决方案没有太大区别,但我想表明您可以在case/esac 语句的匹配阶段做任何事情.

$ 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=1a' <<<$SERVER))echo "Web Server";;
  $(awk 'a=0/db-[0-9]*.host.com/a=1a' <<<$SERVER))echo "DB Server";;
  $(awk 'a=0/bk-[0-9]*.host.com/a=1a' <<<$SERVER))echo "Backup Server";;
  *)echo "Unknown server";;
esac

#################

ws-23.host.com
Web Server

【讨论】:

【参考方案7】:

作为参考,但是这在answer 中已经提到,来自man bash 模式匹配部分提供了用于创建复合模式的规则:

可以使用以下一种或多种子模式形成复合模式: ?(模式列表) 匹配零次或一次给定模式。 *(模式列表) 匹配给定模式的零次或多次出现。 +(模式列表) 匹配给定模式的一次或多次出现。 @(模式列表) 匹配给定模式之一。 !(模式列表) 匹配除给定模式之一之外的任何内容。

但是使用这些扩展模式匹配需要启用extglob shell 选项。

这是当前问题的代码示例:

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;

另外,这个:shopt | grep extglob 可用于检查其默认值。

【讨论】:

你可以只使用shopt extglob来查看是否设置好了,不需要grep 您不必转义点。

以上是关于Bash case 语句中的正则表达式的主要内容,如果未能解决你的问题,请参考以下文章

在 case 语句中使用正则表达式提取动态内容

linux学习第4天(自习)

bash 正则表达式进阶--egrep

在 redshift 中使用正则表达式和 casestatements 语句

bash 中的正则表达式量词——简单与扩展匹配 n 次

使用 linux 和 AIX 的正则表达式替换 bash 脚本中的字符串