在 bash 中一起使用大小写和数组

在 bash 中一起使用大小写和数组

是否可以使用 检查变量是否包含在数组中case?我想做类似的事情

ARR=( opt1 opt2 opt3 );

case $1 in
    $ARR)
        echo "Option is contained in the array";
    *)
        echo "Option is not contained in the array";
esac

答案1

ksh93, 感谢这个错误, 你可以做:

IFS='|'
ARR=( opt1 opt2 opt3 )

IFS='|'
case $1 in
  (@("${ARR[*]}"))
    echo "Option is contained in the array";;
  (*)
    echo "Option is not contained in the array";;
esac

(我不会依赖它,因为该错误将来可能会得到修复)。

有了zsh,你可以这样做:

case ${ARR[(Ie)$1]}
  (0)
    echo "Option is not contained in the array";;
  (*)
    echo "Option is contained in the array";;
esac

(不过,您可能更愿意if (( $ARR[(Ie)$1] )); then echo is present...在此处使用而不是案例构造)。

${array[(I)pattern]}返回与数组中模式匹配的最后一个元素的索引,否则返回 0。这e旗帜是为了精确的匹配(相对于图案匹配)。

对于bash, ksh, yash, zsh,如果您准备好假设$ARR并且$1不包含像 , 这样的特定字符@,并且该字符$ARR不会为空,您可以这样做:

IFS=@
case "@${ARR[*]}@" in
  (*"@$1@"*)
    echo "Option is contained in the array";;
  (*)
    echo "Option is not contained in the array";;
esac

使用bash -O extglob, zsh -o kshglob -o globsubst,您可以定义一个根据数组元素构建模式的助手:

arraypat() {
  awk '
    BEGIN{
      if (ARGC <= 1) print "!(*)"
      else {
        for (i = 1; i < ARGC; i++) {
          gsub(/[][|<>\\?*()]/, "[&]", ARGV[i])
          s = s sep ARGV[i]
          sep = "|"
        }
        print "@(" s ")"
      }
    }' "$@"
}

case $1 in
  ($(arraypat "${ARR[@]}"))
    echo "Option is contained in the array";;
  (*)
    echo "Option is not contained in the array";;
esac

答案2

并不是真正以紧凑且易于使用的方式。请记住,在您的示例中$ARR,它将仅扩展到数组的第一个元素。opt1

您可以使用"${ARR[@]}",但是使用您的数据可能会给字符串带来误报1 opt

对于更新版本的bash,您可以考虑使用关联数组:

declare -A arr
arr=( [opt1]=1 [opt2]=1 [opt3]=1 )

if [[ "${arr[$1]}" -eq 1 ]]; then
   # $1 is a key in arr
else
   # is not
fi

答案3

你为什么要这样做case?它用于字符串模式匹配,而不是每个元素匹配。

坦率地说,如果您经常需要“包含”测试并因此想要缩短它,只需将困难的部分放在函数中,而不是使用丑陋的解决方法:

#!/bin/bash
ARR=( foo bar doo );

contains() {
        typeset _x;
        typeset -n _A="$1"
        for _x in "${_A[@]}" ; do
                [ "$_x" = "$2" ] && return 0
        done
        return 1
}

if contains ARR "$1" ; then
        echo "\"$1\" is contained in ARR"
else
        echo "\"$1\" not contained in ARR"
fi

(这也应该适用于ksh

答案4

对于bash用户来说,可以使用非短路算;;&子;它的子句中不case直接支持数组,但它相当优雅:

ARR=( opt1 opt2 opt3 );

case $1 in
    *)
        [[ ${ARR[*]} =~ $1 ]] \
            && echo "Option is contained in the array" \
            && exit 0
        ;;&

    *)
        echo "Option is not contained in the array"
        ;;
esac

注意;;&(即非短路)确保$1根据后续案例条款进行评估;这需要exit 0return 0在函数/源文件中使用)跳过后续

相关内容