Проверьте, содержит ли массив Bash значение - PullRequest
353 голосов
/ 10 сентября 2010

В Bash, какой самый простой способ проверить, содержит ли массив определенное значение?

Редактировать : С помощью ответов и комментариев после некоторого тестирования я придумал следующее:

function contains() {
    local n=$#
    local value=${!n}
    for ((i=1;i < $#;i++)) {
        if [ "${!i}" == "${value}" ]; then
            echo "y"
            return 0
        fi
    }
    echo "n"
    return 1
}

A=("one" "two" "three four")
if [ $(contains "${A[@]}" "one") == "y" ]; then
    echo "contains one"
fi
if [ $(contains "${A[@]}" "three") == "y" ]; then
    echo "contains three"
fi

Не уверен,лучшее решение, но, похоже, работает.

Ответы [ 32 ]

340 голосов
/ 20 декабря 2011

Ниже приведена небольшая функция для достижения этой цели.Строка поиска является первым аргументом, а остальные - элементами массива:

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
336 голосов
/ 13 марта 2013

Преимущество этого подхода состоит в том, что нет необходимости циклически перебирать все элементы (по крайней мере, явно). Но поскольку array_to_string_internal() в array.c по-прежнему перебирает элементы массива и объединяет их в строку, это, вероятно, не более эффективно, чем предложенные решения для циклического анализа, но более читабельно.

if [[ " ${array[@]} " =~ " ${value} " ]]; then
    # whatever you want to do when arr contains value
fi

if [[ ! " ${array[@]} " =~ " ${value} " ]]; then
    # whatever you want to do when arr doesn't contain value
fi

Обратите внимание, что в тех случаях, когда искомым значением является одно из слов в элементе массива с пробелами, оно даст ложные срабатывания. Например

array=("Jack Brown")
value="Jack"

Регулярное выражение будет видеть Jack как находящееся в массиве, хотя это не так. Поэтому вам придется изменить IFS и символы-разделители в своем регулярном выражении, если вы все еще хотите использовать это решение, например,

IFS=$'\t'
array=("Jack Brown\tJack Smith")
unset IFS

value="Jack Smith"

if [[ "\t${array[@]}\t" =~ "\t${value}\t" ]]; then
    echo "yep, it's there"
fi
59 голосов
/ 11 сентября 2010
$ myarray=(one two three)
$ case "${myarray[@]}" in  *"two"*) echo "found" ;; esac
found
39 голосов
/ 10 сентября 2010
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
18 голосов
/ 27 января 2013

Если вам нужна производительность, вы не хотите перебирать весь массив каждый раз при поиске.

В этом случае вы можете создать ассоциативный массив (хеш-таблицу или словарь), который представляет индекс этого массива. То есть он отображает каждый элемент массива в свой индекс в массиве:

make_index () {
  local index_name=$1
  shift
  local -a value_array=("$@")
  local i
  # -A means associative array, -g means create a global variable:
  declare -g -A ${index_name}
  for i in "${!value_array[@]}"; do
    eval ${index_name}["${value_array[$i]}"]=$i
  done
}

Тогда вы можете использовать это так:

myarray=('a a' 'b b' 'c c')
make_index myarray_index "${myarray[@]}"

И проверить членство вот так:

member="b b"
# the "|| echo NOT FOUND" below is needed if you're using "set -e"
test "${myarray_index[$member]}" && echo FOUND || echo NOT FOUND

Или также:

if [ "${myarray_index[$member]}" ]; then 
  echo FOUND
fi

Обратите внимание, что это решение работает правильно, даже если в проверенном значении или в значениях массива есть пробелы.

В качестве бонуса вы также получаете индекс значения в массиве с помощью:

echo "<< ${myarray_index[$member]} >> is the index of $member"
16 голосов
/ 19 января 2015

Я обычно просто использую:

inarray=$(echo ${haystack[@]} | grep -o "needle" | wc -w)

ненулевое значение указывает, что совпадение найдено.

14 голосов
/ 29 ноября 2017

Однолинейное решение

printf '%s\n' ${myarray[@]} | grep -P '^mypattern$'

Пояснение

Оператор printf печатает каждый элемент массива в отдельной строке.

Оператор grep использует специальные символы ^ и $, чтобы найти строку, содержащую точно шаблон, заданный как mypattern (не больше, не меньше).


Usage

Чтобы поместить это в if ... then выражение:

if printf '%s\n' ${myarray[@]} | grep -q -P '^mypattern$'; then
    # ...
fi

Я добавил флаг -q в выражение grep, чтобы он не печатал совпадения; это просто будет относиться к существованию совпадения как к «истинному».

11 голосов
/ 17 июля 2012

Еще один вкладыш без функции:

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

пример:

some_words=( these are some words )
find_in_array word "${some_words[@]}" || echo "expected missing! since words != word"
11 голосов
/ 10 сентября 2010

Существует пример кода, который показывает, как заменить подстроку из массива .Вы можете сделать копию массива и попытаться удалить целевое значение из копии.Если копия и оригинал отличаются, то целевое значение существует в исходной строке.

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

10 голосов
/ 23 февраля 2011

Вот небольшой вклад:

array=(word "two words" words)  
search_string="two"  
match=$(echo "${array[@]:0}" | grep -o $search_string)  
[[ ! -z $match ]] && echo "found !"  

Примечание: этот способ не различает падеж "два слова", но это не требуется в вопросе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...