我想在 case 语句中使用变量作为条件。类似于:
#!/bin/sh
ALLOWED_SERVICES=tomcat6|james;
case $1 in
$ALLOWED_SERVICES )
service $1 restart
;;
* )
echo "Unsupported argument"
;;
esac
这不起作用。当脚本以tomcat6例如,它超出了“没有依据的论点”消息。但是当案例条件是硬编码时,它可以正常工作:
case $1 in
tomcat6|james )
service $1 restart
;;
* )
echo "Unsupported argument"
;;
esac
在这种情况下可以使用变量吗?
答案1
问题是,变量扩展和模式扩展都需要在匹配之前完成,但这在这里行不通。如果您有最新版本的bash
可用,则可以使用正则表达式匹配:
#!/bin/bash
ALLOWED_SERVICES="tomcat6|james"
if [[ $ALLOWED_SERVICES =~ $1 ]]; then
service $1 restart
else
echo "Unsupported argument"
fi
shopt -s nocasematch
在之前添加if
以使匹配不区分大小写。
答案2
tomcat6
您的第一个 clode 块将无法工作,因为它将尝试通过命令传输输出james
。
无论如何,case
这可能不是合适的工具。使用数组,然后检查它:
#!/bin/bash
declare -a ALLOWED_SERVICES
ALLOWED_SERVICES=(james tomcat6)
for servicename in ${ALLOWED_SERVICES[*]};
do
if [ "${servicename}" == "${1}" ];
then
service $1 restart
exit
fi
done
echo $0: Error: service \"$1\" not recognized
编辑:另外:使用 bash :-)
答案3
分隔多个选项的|
是 shell 语法的一部分。您不能让它来自字符串:字符串必须与|
内部字符匹配。
您可以做的是检查服务名称是否作为子字符串出现在允许的服务列表中,并由分隔符包围。换句话说,检查允许的服务列表是否包含服务作为子字符串。如果服务名称是列表中的第一个或最后一个,请在服务名称周围加上分隔符。
case "$1" in
*\|*) echo 1>&2 "$0: Invalid service name: $1"; exit 2;;
esac
case "|$ALLOWED_SERVICES|" in
*"|$1|"*) service "$1" restart;;
*) echo 1>&2 "$0: Unknown or forbidden service: $1"; exit 2;;
esac
答案4
您可以在 case 条件中使用变量,但不能通过这种方式传递替代方案。实现您想要的一种方法是使用 eval:
#!/bin/sh
ALLOWED_SERVICES="tomcat6|james";
SERVICE="unknown"
[ -n "$1" ] && SERVICE="$1"
CHECKSRV=$(echo $SERVICE | sed 's/[a-z0-9_]*//i')
[ -n "$CHECKSRV" ] && exit 2
eval "
case \"$SERVICE\" in
${ALLOWED_SERVICES} )
service \"$SERVICE\" restart
;;
* )
echo \"Unsupported argument\"
;;
esac
"
我个人更喜欢使用 eval 的另一种解决方案,但考虑到使用 sed 过滤器的检查,您应该可以继续。