在Bash中,测试数组是否包含某个值的最简单方法是什么?
当前回答
没有'grep'和循环的一行检查
if ( dlm=$'\x1F' ; IFS="$dlm" ; [[ "$dlm${array[*]}$dlm" == *"$dlm${item}$dlm"* ]] ) ; then
echo "array contains '$item'"
else
echo "array does not contain '$item'"
fi
这种方法既不使用grep这样的外部实用程序,也不使用循环。
这里发生的是:
we use a wildcard substring matcher to find our item in the array that is concatenated into a string; we cut off possible false positives by enclosing our search item between a pair of delimiters; we use a non-printable character as delimiter, to be on the safe side; we achieve our delimiter being used for array concatenation too by temporary replacement of the IFS variable value; we make this IFS value replacement temporary by evaluating our conditional expression in a sub-shell (inside a pair of parentheses)
其他回答
扩展上面来自Sean DiSanti的答案,我认为下面是一个简单而优雅的解决方案,它避免了对数组进行循环,并且不会由于部分匹配而给出假阳性
function is_in_array {
local ELEMENT="${1}"
local DELIM=","
printf "${DELIM}%s${DELIM}" "${@:2}" | grep -q "${DELIM}${ELEMENT}${DELIM}"
}
可以这样称呼:
$ haystack=("needle1" "needle2" "aneedle" "spaced needle")
$ is_in_array "needle" "${haystack[@]}"
$ echo $?
1
$ is_in_array "needle1" "${haystack[@]}"
$ echo $?
0
for i in "${array[@]}"
do
if [ "$i" -eq "$yourValue" ] ; then
echo "Found"
fi
done
字符串:
for i in "${array[@]}"
do
if [ "$i" == "$yourValue" ] ; then
echo "Found"
fi
done
下面的代码检查给定值是否在数组中,并返回其从零开始的偏移量:
A=("one" "two" "three four")
VALUE="two"
if [[ "$(declare -p A)" =~ '['([0-9]+)']="'$VALUE'"' ]];then
echo "Found $VALUE at offset ${BASH_REMATCH[1]}"
else
echo "Couldn't find $VALUE"
fi
匹配是在完整的值上完成的,因此设置VALUE="three"将不匹配。
我提出了这个方法,它只能在zsh中工作,但我认为一般方法是不错的。
arr=( "hello world" "find me" "what?" )
if [[ "${arr[@]/#%find me/}" != "${arr[@]}" ]]; then
echo "found!"
else
echo "not found!"
fi
只有当${arr[@]/#pattern/}开始或${arr[@]/%pattern/}结束时,才能从每个元素中取出模式。这两个替换可以在bash中工作,但同时${arr[@]/#%pattern/}只能在zsh中工作。
如果修改后的数组等于原始数组,则不包含该元素。
编辑:
这个在bash中工作:
function contains () {
local arr=(${@:2})
local el=$1
local marr=(${arr[@]/#$el/})
[[ "${#arr[@]}" != "${#marr[@]}" ]]
}
在替换之后,它比较两个数组的长度。如果数组包含该元素,则替换将完全删除该元素,并且计数将不同。
如果您想做一个快速而复杂的测试,看看是否值得遍历整个数组以获得精确匹配,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”什么的)将没有输出。