在Bash中,测试数组是否包含某个值的最简单方法是什么?
当前回答
结合Beorn Harris和loentar的回答,我们得出了一个更有趣的单行测试:
delim=$'\x1F' # define a control code to be used as more or less reliable delimiter
if [[ "${delim}${array[@]}${delim}" =~ "${delim}a string to test${delim}" ]]; then
echo "contains 'a string to test'"
fi
它不使用额外的函数,不替换测试,并添加了额外的保护,防止使用控制代码作为分隔符偶尔出现错误匹配。
UPD:感谢@ChrisCogdon的注意,这个错误的代码被重写并以https://stackoverflow.com/a/58527681/972463的形式发布。
其他回答
$ myarray=(one two three)
$ case "${myarray[@]}" in *"two"*) echo "found" ;; esac
found
如果您想做一个快速而复杂的测试,看看是否值得遍历整个数组以获得精确匹配,Bash可以像对待标量一样对待数组。测试标量中的匹配项,如果没有,则跳过循环节省时间。显然你会得到假阳性。
array=(word "two words" words)
if [[ ${array[@]} =~ words ]]
then
echo "Checking"
for element in "${array[@]}"
do
if [[ $element == "words" ]]
then
echo "Match"
fi
done
fi
这将输出“Checking”和“Match”。使用array=(word "two words" something),它只会输出"Checking"。使用array=(单词“two widgets”什么的)将没有输出。
这是一个小小的贡献:
array=(word "two words" words)
search_string="two"
match=$(echo "${array[@]:0}" | grep -o $search_string)
[[ ! -z $match ]] && echo "found !"
注意:这种方法不区分大小写“两个单词”,但在问题中不需要这样做。
OP自己添加了以下答案,并附上了评论:
在回答和评论的帮助下,经过一些测试,我得出了这个结论:
function contains() {
local n=$#
local value=${!n}
for ((i=1;i < $#;i++)) {
if [ "${!i}" == "${value}" ]; then
echo "y"
return 0
fi
}
echo "n"
return 1
}
A=("one" "two" "three four")
if [ $(contains "${A[@]}" "one") == "y" ]; then
echo "contains one"
fi
if [ $(contains "${A[@]}" "three") == "y" ]; then
echo "contains three"
fi
我看到了一些解决这个问题的方法。
对于使用grep的索引数组
grep ${value} <<< ${array[*]} && true || false
对于使用grep的关联数组键
grep ${value} <<< "${!array[*]}" && true || false
我们可以使用awk,但它可能太过了。
awk --assign "v=${value}" '$v~$0 {print true}' <<<"${!array[*]}
Case语句。
case "${array[*]}" in (*${value}*) true ;; (*) false ;; esac
Bash条件表达式在ksh88风格双方括号:
[[ ${array[@]} =~ ${value} ]] && true || false
注意:顺序很重要,正则表达式在=~ match运算符的右边。
Bash for循环
for ((i=0;i<"${#array[*]}";i++)) ; [[ ${array[i]} = $value ]] && break 0 &> /dev/null || continue; done
注意,在这种特殊情况下,真逻辑是颠倒的,即1=真,0=假。这是因为我们使用break 0强制break内置除true之外的退出代码,除非break n参数小于1,否则总是如此。我们必须要打破循环,我们想要一个布尔退出码除了默认的'true',所以在这种情况下,我们翻转了逻辑。因此,使用具有返回true语义的函数可能更有意义。