在Bash中,测试数组是否包含某个值的最简单方法是什么?
当前回答
以下是我对这个问题的看法。以下是简短的版本:
function arrayContains() {
local haystack=${!1}
local needle="$2"
printf "%s\n" ${haystack[@]} | grep -q "^$needle$"
}
长一点的版本,我觉得看起来更舒服。
# With added utility function.
function arrayToLines() {
local array=${!1}
printf "%s\n" ${array[@]}
}
function arrayContains() {
local haystack=${!1}
local needle="$2"
arrayToLines haystack[@] | grep -q "^$needle$"
}
例子:
test_arr=("hello" "world")
arrayContains test_arr[@] hello; # True
arrayContains test_arr[@] world; # True
arrayContains test_arr[@] "hello world"; # False
arrayContains test_arr[@] "hell"; # False
arrayContains test_arr[@] ""; # False
其他回答
这对我来说很管用:
# 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
这是一个小小的贡献:
array=(word "two words" words)
search_string="two"
match=$(echo "${array[@]:0}" | grep -o $search_string)
[[ ! -z $match ]] && echo "found !"
注意:这种方法不区分大小写“两个单词”,但在问题中不需要这样做。
The answer with most votes is very concise and clean, but it can have false positives when a space is part of one of the array elements. This can be overcome when changing IFS and using "${array[*]}" instead of "${array[@]}". The method is identical, but it looks less clean. By using "${array[*]}", we print all elements of $array, separated by the first character in IFS. So by choosing a correct IFS, you can overcome this particular issue. In this particular case, we decide to set IFS to an uncommon character $'\001' which stands for Start of Heading (SOH)
$ array=("foo bar" "baz" "qux")
$ IFS=$'\001'
$ [[ "$IFS${array[*]}$IFS" =~ "${IFS}foo${IFS}" ]] && echo yes || echo no
no
$ [[ "$IFS${array[*]}$IFS" =~ "${IFS}foo bar${IFS}" ]] && echo yes || echo no
yes
$ unset IFS
这解决了大多数假阳性问题,但需要一个好的IFS选择。
注意:如果之前设置了IFS,最好保存并重新设置,而不是使用未设置的IFS
相关:
访问bash命令行参数$@ vs $*
这种方法的优点是不需要遍历所有元素(至少不是显式地)。但是由于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"
回答完之后,我读到了另一个我特别喜欢的答案,但它有缺陷,遭到了不好评。我受到了启发,这里有两种可行的新方法。
array=("word" "two words") # let's look for "two words"
使用grep和printf:
(printf '%s\n' "${array[@]}" | grep -x -q "two words") && <run_your_if_found_command_here>
使用:
(for e in "${array[@]}"; do [[ "$e" == "two words" ]] && exit 0; done; exit 1) && <run_your_if_found_command_here>
对于not_found结果,添加|| <run_your_if_notfound_command_here>