Подтвердить что ты не робот

Проверьте, присутствует ли элемент в массиве Bash

Мне было интересно, есть ли эффективный способ проверить, присутствует ли элемент в массиве в Bash? Я ищу что-то похожее на то, что я могу сделать в Python, например:

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

if 'd' in arr:
    do your thing
else:
    do something

Я видел решения с использованием ассоциативного массива для bash для bash 4+, но мне интересно, есть ли там другое решение.

Пожалуйста, поймите, что я знаю, что тривиальное решение состоит в итерации в массиве, но я не хочу этого.

4b9b3361

Ответ 1

Вы можете сделать:

if [[ " ${arr[*]} " == *" d "* ]]; then
    echo "arr contains d"
fi

Это даст ложные срабатывания, например, если вы ищете "a" - эта подстрока находится в объединенной строке, но не как элемент массива. Эта дилемма будет происходить для любого выбранного ограничителя.

Самый безопасный способ - перебрать массив, пока не найдет элемент:

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

Ответ 2

Очевидные оговорки в сторону, если ваш массив действительно похож на тот, что был выше, вы могли бы сделать

if [[ ${arr[*]} =~ d ]]
then
  do your thing
else
  do something
fi

Ответ 3

1) Инициализировать массив arr и добавить элементы

2) задайте переменную для поиска SEARCH_STRING

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

Ответ 4

Если элементы массива не содержат пробелов, другое (возможно, более читаемое) решение будет:

if echo ${arr[@]} | grep -q -w "d"; then 
    echo "is in array"
else 
    echo "is not in array"
fi

Ответ 5

array=("word" "two words") # let look for "two words"

с помощью grep и printf:

(printf '%s\n' "${array[@]}" | grep -x -q "two words") && <run_your_if_found_command_here>

с помощью for:

(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>

Ответ 6

Вот еще один способ, который может быть быстрее, с точки зрения времени вычисления, чем повторение. Не уверен. Идея состоит в том, чтобы преобразовать массив в строку, усечь его и получить размер нового массива.

Например, чтобы найти индекс '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`

Ответ 7

FWIW, вот что я использовал:

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

Это работает там, где нет разделителей в любом элементе массива или в целевой точке поиска. Мне не нужно было решать общий случай для моего приложения.

Ответ 8

Поскольку bash не имеет встроенного значения in операторе массива, а оператор =~ или нотация [[ "${array[@]" == *"${item}"* ]] меня смущают, я обычно комбинирую grep с здесь-строкой:

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