Проверьте, присутствует ли элемент в массиве Bash
Мне было интересно, есть ли эффективный способ проверить, присутствует ли элемент в массиве в Bash? Я ищу что-то похожее на то, что я могу сделать в Python, например:
arr = ['a','b','c','d']
if 'd' in arr:
do your thing
else:
do something
Я видел решения с использованием ассоциативного массива для bash для bash 4+, но мне интересно, есть ли там другое решение.
Пожалуйста, поймите, что я знаю, что тривиальное решение состоит в итерации в массиве, но я не хочу этого.
Ответы
Ответ 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