我试图在bash中编写一个脚本,检查用户输入的有效性。 我想将输入(变量x)匹配到一个有效值列表。

我现在想到的是:

for item in $list
do
    if [ "$x" == "$item" ]; then
        echo "In the list"
        exit
    fi
done

我的问题是,如果有更简单的方法, 对于大多数编程语言,类似list.contains(x)。

列表是:

list="11 22 33"

我的代码将只对这些值回显消息,因为list被视为数组而不是字符串, 所有的字符串操作都将验证1,而我希望它失败。


当前回答

简单oneliner ...

if [[ " 11 22 33 " == *" ${x} "* ]]; then echo "${x} is in the list"; fi;

在fi之前添加:else echo "${x}不在列表中";

其他回答

如果您的值列表将硬编码在脚本中,那么测试用例相当简单。下面是一个简短的例子,你可以根据自己的需求进行调整:

for item in $list
do
    case "$x" in
      item1|item2)
        echo "In the list"
        ;;
      not_an_item)
        echo "Error" >&2
        exit 1
        ;;
    esac
done

如果列表在运行时是一个数组变量,那么其他答案中的一个可能更适合。

shell内置的compgen可以在这里提供帮助。它可以接受带有-W标志的列表,并返回它找到的任何潜在匹配项。

# My list can contain spaces so I want to set the internal
# file separator to newline to preserve the original strings.
IFS=$'\n'

# Create a list of acceptable strings.
accept=( 'foo' 'bar' 'foo bar' )

# The string we will check
word='foo'

# compgen will return a list of possible matches of the 
# variable 'word' with the best match being first.
compgen -W "${accept[*]}" "$word"

# Returns:
# foo
# foo bar

我们可以编写一个函数来测试字符串是否等于可接受字符串的最佳匹配。这允许您分别为通过或失败返回0或1。

function validate {
  local IFS=$'\n'
  local accept=( 'foo' 'bar' 'foo bar' )
  if [ "$1" == "$(compgen -W "${accept[*]}" "$1" | head -1)" ] ; then
    return 0
  else
    return 1
  fi
}

现在您可以编写非常清晰的测试来验证字符串是否可接受。

validate "blah" || echo unacceptable

if validate "foo" ; then
  echo acceptable
else 
  echo unacceptable
fi

之前的答案没有使用tr,我发现它对grep很有用。假设列表中的项以空格分隔,检查精确匹配:

echo $mylist | tr ' ' '\n' | grep -F -x -q "$myitem"

如果条目在列表中,这将返回退出代码0,如果不在列表中,则返回退出代码1。

最好将它作为函数使用:

_contains () {  # Check if space-separated list $1 contains line $2
  echo "$1" | tr ' ' '\n' | grep -F -x -q "$2"
}

mylist="aa bb cc"

# Positive check
if _contains "${mylist}" "${myitem}"; then
  echo "in list"
fi

# Negative check
if ! _contains "${mylist}" "${myitem}"; then
  echo "not in list"
fi

如何

echo $list | grep -w -q $x

您可以检查输出或$?上面的线来做决定。

Grep -w检查整个单词模式。添加-q可以防止列表回显。

[[ $list =~ (^|[[:space:]])$x($|[[:space:]]) ]] && echo 'yes' || echo 'no'

或者创建一个函数:

contains() {
    [[ $1 =~ (^|[[:space:]])$2($|[[:space:]]) ]] && exit(0) || exit(1)
}

使用它:

contains aList anItem
echo $? # 0: match, 1: failed