在Bash中,测试数组是否包含某个值的最简单方法是什么?
当前回答
保持简单:
Array1=( "item1" "item2" "item3" "item-4" )
var="item3"
count=$(echo ${Array1[@]} | tr ' ' '\n' | awk '$1 == "'"$var"'"{print $0}' | wc -l)
[ $count -eq 0 ] && echo "Not found" || echo "found"
其他回答
我通常编写这类实用程序来操作变量的名称,而不是变量的值,这主要是因为bash不能通过引用传递变量。
下面是一个使用数组名称的版本:
function array_contains # array value
{
[[ -n "$1" && -n "$2" ]] || {
echo "usage: array_contains <array> <value>"
echo "Returns 0 if array contains value, 1 otherwise"
return 2
}
eval 'local values=("${'$1'[@]}")'
local element
for element in "${values[@]}"; do
[[ "$element" == "$2" ]] && return 0
done
return 1
}
这样,问题示例就变成:
array_contains A "one" && echo "contains one"
etc.
别胡闹了!使您的解决方案简单、干净和可重用。
这些函数负责索引数组和关联数组。可以通过将搜索算法从线性搜索升级为二进制搜索(用于大型数据集)来改进它们。
##
# Determines if a value exists in an array.
###
function hasArrayValue ()
{
local -r needle="{$1:?}"
local -nr haystack="{$2:?}" # Where you pass by reference to get the entire array in one argument.
# Linear search. Upgrade to binary search for large datasets.
for value in "${haystack[@]}"; do
if [[ "$value" == "$needle" ]]; then
return 0
fi
done
return 1
}
##
# Determines if a value exists in an associative array / map.
###
function hasMapValue ()
{
local -r needle="{$1:?}"
local -nr haystack="{$2:?}"
# Linear search. Upgrade to binary search for large datasets.
for value in "${haystack[@]}"; do
if [[ $value == $needle ]]; then
return 0
fi
done
return 1
}
是的,同样的逻辑,但在处理bash时,如果函数的名称可以让您知道迭代的对象(或不迭代的对象),则可能(可能)有用。
这对我来说很管用:
# traditional system call return values-- used in an `if`, this will be true when returning 0. Very Odd.
contains () {
# odd syntax here for passing array parameters: http://stackoverflow.com/questions/8082947/how-to-pass-an-array-to-a-bash-function
local list=$1[@]
local elem=$2
# echo "list" ${!list}
# echo "elem" $elem
for i in "${!list}"
do
# echo "Checking to see if" "$i" "is the same as" "${elem}"
if [ "$i" == "${elem}" ] ; then
# echo "$i" "was the same as" "${elem}"
return 0
fi
done
# echo "Could not find element"
return 1
}
示例调用:
arr=("abc" "xyz" "123")
if contains arr "abcx"; then
echo "Yes"
else
echo "No"
fi
下面是实现这一点的一个小函数。搜索字符串是第一个参数,其余是数组元素:
set +e #otherwise the script will exit on error
containsElement () {
local e match="$1"
shift
for e; do [[ "$e" == "$match" ]] && return 0; done
return 1
}
该函数的测试运行如下:
$ array=("something to search for" "a string" "test2000")
$ containsElement "a string" "${array[@]}"
$ echo $?
0
$ containsElement "blaha" "${array[@]}"
$ echo $?
1
这种方法的优点是不需要遍历所有元素(至少不是显式地)。但是由于array.c中的array_to_string_internal()仍然循环遍历数组元素并将它们连接到一个字符串中,因此它可能并不比所提出的循环解决方案更有效,但它更具可读性。
if [[ " ${array[*]} " =~ " ${value} " ]]; then
# whatever you want to do when array contains value
fi
if [[ ! " ${array[*]} " =~ " ${value} " ]]; then
# whatever you want to do when array doesn't contain value
fi
请注意,如果您正在搜索的值是带有空格的数组元素中的某个单词,则会给出假阳性。例如
array=("Jack Brown")
value="Jack"
正则表达式将“Jack”视为在数组中,即使它不在数组中。所以你必须改变IFS和正则表达式上的分隔符如果你仍然想使用这个解决方案,就像这样
IFS="|"
array=("Jack Brown${IFS}Jack Smith")
value="Jack"
if [[ "${IFS}${array[*]}${IFS}" =~ "${IFS}${value}${IFS}" ]]; then
echo "true"
else
echo "false"
fi
unset IFS # or set back to original IFS if previously set
这将打印“false”。
显然,这也可以用作测试语句,允许将其表示为一行程序
[[ " ${array[*]} " =~ " ${value} " ]] && echo "true" || echo "false"