bash/bourne 中是否有“in”运算符?

mrj*_*per 18 bash shell-script bourne-shell

我正在寻找一个像这样工作的“in”运算符:

if [ "$1" in ("cat","dog","mouse") ]; then
    echo "dollar 1 is either a cat or a dog or a mouse"
fi
Run Code Online (Sandbox Code Playgroud)

与使用多个“或”测试相比,这显然是一个更短的语句。

ste*_*ver 34

您可以使用case...esac

$ cat in.sh 
#!/bin/bash

case "$1" in 
  "cat"|"dog"|"mouse")
    echo "dollar 1 is either a cat or a dog or a mouse"
  ;;
  *)
    echo "none of the above"
  ;;
esac
Run Code Online (Sandbox Code Playgroud)

前任。

$ ./in.sh dog
dollar 1 is either a cat or a dog or a mouse
$ ./in.sh hamster
none of the above
Run Code Online (Sandbox Code Playgroud)

使用ksh, bash -O extglobor zsh -o kshglob,您还可以使用扩展的 glob 模式:

if [[ "$1" = @(cat|dog|mouse) ]]; then
  echo "dollar 1 is either a cat or a dog or a mouse"
else
  echo "none of the above"
fi
Run Code Online (Sandbox Code Playgroud)

使用bash, ksh93or zsh,您还可以使用正则表达式比较:

if [[ "$1" =~ ^(cat|dog|mouse)$ ]]; then
  echo "dollar 1 is either a cat or a dog or a mouse"
else
  echo "none of the above"
fi
Run Code Online (Sandbox Code Playgroud)

  • @mrjayviper 双括号是一个扩展的测试结构 - AFAIK 正则表达式运算符 `=~` 在 POSIX 单括号测试中无效 (2认同)
  • @StéphaneChazelas 因为至少 bash 4.1-alpha 不需要显式设置 extglog。[来自 bash 更改](https://tiswww.case.edu/php/chet/bash/CHANGES):*s。将模式参数解析为 [[ 命令的 == 和 != 运算符时,暂时强制打开 extglob,以实现兼容性。* (2认同)

ImH*_*ere 11

bash 中没有“in”测试,但有一个正则表达式测试(不在 bourne 中):

if [[ $1 =~ ^(cat|dog|mouse)$ ]]; then
    echo "dollar 1 is either a cat or a dog or a mouse"
fi
Run Code Online (Sandbox Code Playgroud)

并且通常使用变量编写(引用问题较少):

regex='^(cat|dog|mouse)$'

if [[ $1 =~ $regex ]]; then
    echo "dollar 1 is either a cat or a dog or a mouse"
fi
Run Code Online (Sandbox Code Playgroud)

对于较旧的 Bourne shell,您需要使用大小写匹配:

case $1 in
    cat|dog|mouse)   echo "dollar 1 is either a cat or a dog or a mouse";;
esac
Run Code Online (Sandbox Code Playgroud)


ilk*_*chu 8

case如果您有一组固定的要匹配的宠物,则使用 a很好。但是,如果您需要在运行时构建模式,它将不起作用,因为case它不会从扩展参数中解释交替。

这将只匹配文字字符串cat|dog|mouse

patt='cat|dog|mouse'
case $1 in 
        $patt) echo "$1 matches the case" ;; 
esac
Run Code Online (Sandbox Code Playgroud)

但是,您可以使用具有正则表达式匹配的变量。只要变量没有被引用,其中的任何正则表达式运算符都有其特殊含义。

patt='cat|dog|mouse'
if [[ "$1" =~ ^($patt)$ ]]; then
        echo "$1 matches the pattern"
fi
Run Code Online (Sandbox Code Playgroud)

您还可以使用关联数组。检查一个键是否存在是与inBash 提供的运算符最接近的事情。虽然语法有点难看:

declare -A arr
arr[cat]=1
arr[dog]=1
arr[mouse]=1

if [ "${arr[$1]+x}" ]; then
        echo "$1 is in the array"
fi
Run Code Online (Sandbox Code Playgroud)

${arr[$1]+x}扩展为xifarr[$1]已设置,否则为空。


Kus*_*nda 5

可以caseif测试中使用语句,但代码看起来有点麻烦:

if case "$1" in (cat|dog|mouse) true ;; (*) false; esac; then
    printf '"%s" is one of cat, dog or mouse\n' "$1"
else
    printf '"%s" is unknown\n' "$1"
fi
Run Code Online (Sandbox Code Playgroud)

或者稍微短一点,

if ! case "$1" in (cat|dog|mouse) false; esac; then
    printf '"%s" is one of cat, dog or mouse\n' "$1"
else
    printf '"%s" is unknown\n' "$1"
fi
Run Code Online (Sandbox Code Playgroud)

这是使用case子句只是为子句进行模式匹配if。它引入了不必要的真/假测试。

最好只使用case

case "$1" in
    cat|dog|mouse)
        printf '"%s" is one of cat, dog or mouse\n' "$1"
        ;;
    *)
        printf '"%s" is unknown\n' "$1"
esac
Run Code Online (Sandbox Code Playgroud)

不要这样做:

is_one_of () {
    eval "case $1 in ($2) return 0; esac"
    return 1
}

if is_one_of "$1" 'cat|dog|mouse'; then
    printf '"%s" is one of cat, dog or mouse\n' "$1"
else
    printf '"%s" is unknown\n' "$1"
fi
Run Code Online (Sandbox Code Playgroud)

或这个:

is_one_of () (
    word=$1
    shift
    IFS='|'
    eval "case $word in ($*) return 0; esac"
    return 1
)

if is_one_of "$1" cat dog mouse; then
    printf '"%s" is one of cat, dog or mouse\n' "$1"
else
    printf '"%s" is unknown\n' "$1"
fi
Run Code Online (Sandbox Code Playgroud)

...因为您只是添加了更危险的垃圾,只是为了能够if在您的代码中使用一个语句来代替一个完全合理的case语句。