Arrays 检查Bash数组中是否存在元素

Arrays 检查Bash数组中是否存在元素,arrays,bash,shell,search,Arrays,Bash,Shell,Search,我想知道是否有一种有效的方法来检查Bash中的数组中是否存在元素?我正在寻找类似于我在Python中所能做的事情,比如: arr = ['a','b','c','d'] if 'd' in arr: do your thing else: do something 我看到过使用bash的关联数组来解决bash4+的问题,但我想知道是否还有其他解决方案 请理解,我知道最简单的解决方案是在数组中进行迭代,但我不希望这样。除了明显的警告,如果您的数组与上面的一样,您可以这样做 if

我想知道是否有一种有效的方法来检查Bash中的数组中是否存在元素?我正在寻找类似于我在Python中所能做的事情,比如:

arr = ['a','b','c','d']

if 'd' in arr:
    do your thing
else:
    do something
我看到过使用bash的关联数组来解决bash4+的问题,但我想知道是否还有其他解决方案


请理解,我知道最简单的解决方案是在数组中进行迭代,但我不希望这样。

除了明显的警告,如果您的数组与上面的一样,您可以这样做

if[${arr[*]}=~d]]
然后
做你的事
其他的
做点什么
fi
您可以执行以下操作:

if [[ " ${arr[*]} " == *" d "* ]]; then
    echo "arr contains d"
fi
这将导致误报,例如,如果您查找“ab”——该子字符串位于连接的字符串中,但不是作为数组元素。无论您选择什么分隔符,都会出现这种困境

最安全的方法是在数组上循环,直到找到元素:

array_contains () {
    local seeking=$1; shift
    local in=1
    for element; do
        if [[ $element == "$seeking" ]]; then
            in=0
            break
        fi
    done
    return $in
}

arr=(a b c "d e" f g)
array_contains "a b" "${arr[@]}" && echo yes || echo no    # no
array_contains "d e" "${arr[@]}" && echo yes || echo no    # yes
这里有一个“更干净”的版本,您只需传递数组名,而不是它的所有元素

array_contains2 () { 
    local array="$1[@]"
    local seeking=$2
    local in=1
    for element in "${!array}"; do
        if [[ $element == "$seeking" ]]; then
            in=0
            break
        fi
    done
    return $in
}

array_contains2 arr "a b"  && echo yes || echo no    # no
array_contains2 arr "d e"  && echo yes || echo no    # yes

对于关联数组,有一种非常简洁的方法可以测试数组是否包含给定的键:
-v
操作符

$ declare -A arr=( [foo]=bar [baz]=qux )
$ [[ -v arr[foo] ]] && echo yes || echo no
yes
$ [[ -v arr[bar] ]] && echo yes || echo no
no

请参阅手册。

就计算时间而言,还有一种方法可能比迭代更快。不确定。其思想是将数组转换为字符串,截断它,并获得新数组的大小

例如,要查找“d”的索引,请执行以下操作:

arr=(a b c d)    
temp=`echo ${arr[@]}`
temp=( ${temp%%d*} )
index=${#temp[@]}
您可以将其转换为如下函数:

get-index() {

    Item=$1
    Array="$2[@]"

    ArgArray=( ${!Array} )
    NewArray=( ${!Array%%${Item}*} )

    Index=${#NewArray[@]}

    [[ ${#ArgArray[@]} == ${#NewArray[@]} ]] && echo -1 || echo $Index

}
然后你可以打电话:

get-index d arr
它将回响3,这将与:

index=`get-index d arr`

FWIW,我用的是:

expr "${arr[*]}" : ".*\<$item\>"
expr“${arr[*]}”:“*\”

这适用于任何数组项或搜索目标中没有分隔符的情况。我不需要解决我的应用程序的一般情况。

如果数组元素不包含空格,另一个(可能更可读)解决方案是:

if echo ${arr[@]} | grep -q -w "d"; then 
    echo "is in array"
else 
    echo "is not in array"
fi
使用
grep
printf
: 对于未找到的结果,添加
|

1)初始化数组
arr
并添加元素

2) 设置变量以搜索
search\u字符串

3) 检查数组是否包含元素

arr=()
arr+=('a')
arr+=('b')
arr+=('c')

SEARCH_STRING='b'

if [[ " ${arr[*]} " == *"$SEARCH_STRING"* ]];
then
    echo "YES, your arr contains $SEARCH_STRING"
else
    echo "NO, your arr does not contain $SEARCH_STRING"
fi

由于bash在数组操作符和
=~
操作符或
[[“${array[@]”==*“${item}”*]
符号中没有内置的值
,我经常将
grep
与here字符串组合在一起:

colors=('black' 'blue' 'light green')
if grep -q 'black' <<< "${colors[@]}"
then
    echo 'match'
fi


不要把“简明”和“高效”混淆。但是不,在
bash
中没有简明的方法可以用一个简单的数组来做你想做的事情。看看+1可以教你一些新的东西。但是
d
也会匹配
xdy
。@OlafDietsche如果[${arr[*]}=~$(echo'\')]
,就可以通过编写它来解决这个问题。()谢谢,这很有帮助。但是如果我没有其他追随者,我怎么能否定结果呢?这将节省一些冗余代码。@SvenM.if[[!${arr[*]}=~d]]?此代码是否同时适用于数值和字符串值?例如,如果我的数组同时包含字符串和数组,我可以同时搜索它们吗?是的。Bash将以字符串形式处理数值,而不难删除位置参数的第一个元素。在我的实现中,我必须将“${!array}”更改为“${array[@]}”我判断“数组包含”和“数组包含2”建议更安全,因为许多使用GRIP的人返回假阳性。考虑引用<代码> $寻找/代码>,以使它不被认为是模式。+ 1。不错的答案。这个解决方案对我来说检查数字数组中是否存在一个数字。而@ Steven Penny的解决方案在数字数组中不起作用100%。{combined_p2_idx[@]}| grep-q-w$subset_id;然后我同意@willion。这应该是公认的答案。其他选项没有那么可靠。如果数组中有负数,则会出错添加
--
以表示参数结束,负数将不会被视为grepBy far的参数,这是最优雅和可理解的解决方案。工作顺利e对我来说是一个魅力。这是线程中唯一对我有效的回复,谢谢!这非常简洁,我可以将它与
BASH_ARGV
一起使用,来测试某个单词是否作为需要不同一次性设置的参数出现,而不必执行某种类型的
argparse
,这是overkill用于本例。@Querty我不知道为什么这不是最重要的答案。
grep-x…。
使其使用起来最简单。@sec正如上面所演示的@Querty的答案那样,为了避免误报,只需将
-x
添加到grep以匹配整行内容。
(for e in "${array[@]}"; do [[ "$e" == "two words" ]] && exit 0; done; exit 1) && <run_your_if_found_command_here>
arr=()
arr+=('a')
arr+=('b')
arr+=('c')

SEARCH_STRING='b'

if [[ " ${arr[*]} " == *"$SEARCH_STRING"* ]];
then
    echo "YES, your arr contains $SEARCH_STRING"
else
    echo "NO, your arr does not contain $SEARCH_STRING"
fi
colors=('black' 'blue' 'light green')
if grep -q 'black' <<< "${colors[@]}"
then
    echo 'match'
fi
if grep -q 'green' <<< "${colors[@]}"
then
    echo 'should not match, but does'
fi
for color in "${colors[@]}"
do
    if [ "${color}" = 'green' ]
    then
        echo "should not match and won't"
        break
    fi
done

for color in "${colors[@]}"
do
    if [ "${color}" = 'light green' ]
    then
        echo 'match'
        break
    fi
done