在Bash中,测试数组是否包含某个值的最简单方法是什么?
当前回答
@ghostdog74关于使用大小写逻辑检查数组包含特定值的回答的一个小补充:
myarray=(one two three)
word=two
case "${myarray[@]}" in ("$word "*|*" $word "*|*" $word") echo "found" ;; esac
或者打开extglob选项,你可以这样做:
myarray=(one two three)
word=two
shopt -s extglob
case "${myarray[@]}" in ?(*" ")"$word"?(" "*)) echo "found" ;; esac
我们也可以用if语句:
myarray=(one two three)
word=two
if [[ $(printf "_[%s]_" "${myarray[@]}") =~ .*_\[$word\]_.* ]]; then echo "found"; fi
其他回答
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
另一个没有函数的代码:
(for e in "${array[@]}"; do [[ "$e" == "searched_item" ]] && exit 0; done) && echo "found" || echo "not found"
谢谢@Qwerty关于空格的提示!
对应的功能:
find_in_array() {
local word=$1
shift
for e in "$@"; do [[ "$e" == "$word" ]] && return 0; done
return 1
}
例子:
some_words=( these are some words )
find_in_array word "${some_words[@]}" || echo "expected missing! since words != word"
别胡闹了!使您的解决方案简单、干净和可重用。
这些函数负责索引数组和关联数组。可以通过将搜索算法从线性搜索升级为二进制搜索(用于大型数据集)来改进它们。
##
# 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时,如果函数的名称可以让您知道迭代的对象(或不迭代的对象),则可能(可能)有用。
我通常只使用:
inarray=$(echo ${haystack[@]} | grep -o "needle" | wc -w)
非零值表示找到了匹配。
... 实际上,为了解决它不能与needle1和needle2工作的问题,如果你只想要一个精确匹配,没有更多,没有更少,只需在-o后面添加一个w标志,用于整个单词匹配:
inarray=$(echo ${haystack[@]} | grep -ow "needle" | wc -w)
: NeedleInArgs "$needle" "${haystack[@]}"
: NeedleInArgs "$needle" arg1 arg2 .. argN
NeedleInArgs()
{
local a b;
printf -va '\n%q\n' "$1";
printf -vb '%q\n' "${@:2}";
case $'\n'"$b" in (*"$a"*) return 0;; esac;
return 1;
}
使用:
NeedleInArgs "$needle" "${haystack[@]}" && echo "$needle" found || echo "$needle" not found;
对于bash v3.1及以上版本(printf -v支持) 没有分叉,也没有外部程序 没有循环(除了bash中的内部扩展) 适用于所有可能的值和数组,没有异常,没有什么可担心的
也可以直接使用,比如:
if NeedleInArgs "$input" value1 value2 value3 value4;
then
: input from the list;
else
: input not from list;
fi;
对于从v20.5 b到v3.0的bash, printf缺少-v,因此需要额外的2个fork(但不需要执行,因为printf是bash内置的):
NeedleInArgs()
{
case $'\n'"`printf '%q\n' "${@:2}"`" in
(*"`printf '\n%q\n' "$1"`"*) return 0;;
esac;
return 1;
}
注意,我测试了时间:
check call0: n: t4.43 u4.41 s0.00 f: t3.65 u3.64 s0.00 l: t4.91 u4.90 s0.00 N: t5.28 u5.27 s0.00 F: t2.38 u2.38 s0.00 L: t5.20 u5.20 s0.00
check call1: n: t3.41 u3.40 s0.00 f: t2.86 u2.84 s0.01 l: t3.72 u3.69 s0.02 N: t4.01 u4.00 s0.00 F: t1.15 u1.15 s0.00 L: t4.05 u4.05 s0.00
check call2: n: t3.52 u3.50 s0.01 f: t3.74 u3.73 s0.00 l: t3.82 u3.80 s0.01 N: t2.67 u2.67 s0.00 F: t2.64 u2.64 s0.00 L: t2.68 u2.68 s0.00
Call0和call1是对另一个快速pure-bash变体调用的不同变体 Call2在这里。 N=notfound F=firstmatch L=lastmatch 小写字母为短数组,大写字母为长数组
正如您所看到的,这里的这个变体有一个非常稳定的运行时,所以它不太依赖于匹配位置。运行时主要由数组长度决定。搜索变量的运行时高度依赖于匹配位置。所以在边缘情况下,这个变体可以(快得多)。
但非常重要的是,搜索变量的RAM效率更高,因为这里的这个变量总是将整个数组转换为一个大字符串。
所以如果你的内存很紧,你希望大部分比赛都是早期的,那么就不要在这里使用这个。但是,如果您想要一个可预测的运行时,有很长的数组来匹配(期望延迟或根本不匹配),并且双RAM使用也不是太大的问题,那么这里有一些优势。
定时测试脚本:
in_array()
{
local needle="$1" arrref="$2[@]" item
for item in "${!arrref}"; do
[[ "${item}" == "${needle}" ]] && return 0
done
return 1
}
NeedleInArgs()
{
local a b;
printf -va '\n%q\n' "$1";
printf -vb '%q\n' "${@:2}";
case $'\n'"$b" in (*"$a"*) return 0;; esac;
return 1;
}
loop1() { for a in {1..100000}; do "$@"; done }
loop2() { for a in {1..1000}; do "$@"; done }
run()
{
needle="$5"
arr=("${@:6}")
out="$( ( time -p "loop$2" "$3" ) 2>&1 )"
ret="$?"
got="${out}"
syst="${got##*sys }"
got="${got%"sys $syst"}"
got="${got%$'\n'}"
user="${got##*user }"
got="${got%"user $user"}"
got="${got%$'\n'}"
real="${got##*real }"
got="${got%"real $real"}"
got="${got%$'\n'}"
printf ' %s: t%q u%q s%q' "$1" "$real" "$user" "$syst"
[ -z "$rest" ] && [ "$ret" = "$4" ] && return
printf 'FAIL! expected %q got %q\n' "$4" "$ret"
printf 'call: %q\n' "$3"
printf 'out: %q\n' "$out"
printf 'rest: %q\n' "$rest"
printf 'needle: %q\n' "$5"
printf 'arr: '; printf ' %q' "${@:6}"; printf '\n'
exit 1
}
check()
{
printf 'check %q: ' "$1"
run n 1 "$1" 1 needle a b c d
run f 1 "$1" 0 needle needle a b c d
run l 1 "$1" 0 needle a b c d needle
run N 2 "$1" 1 needle "${rnd[@]}"
run F 2 "$1" 0 needle needle "${rnd[@]}"
run L 2 "$1" 0 needle "${rnd[@]}" needle
printf '\n'
}
call0() { chk=("${arr[@]}"); in_array "$needle" chk; }
call1() { in_array "$needle" arr; }
call2() { NeedleInArgs "$needle" "${arr[@]}"; }
rnd=()
for a in {1..1000}; do rnd+=("$a"); done
check call0
check call1
check call2