Проверить, если элемент в массиве в bash

есть хороший способ проверить, если массив содержит элемент в bash (лучше проезжать)?

альтернативно, есть ли другой способ проверить, равно ли число или строка любому из набора предопределенных констант?

17
задан Tgr
15.01.2023 10:28 Количество просмотров материала 3373
Распечатать страницу

6 ответов

в Bash 4 можно использовать ассоциативные массивы:

# set up array of constants
declare -A array
for constant in foo bar baz
do
    array[$constant]=1
done

# test for existence
test1="bar"
test2="xyzzy"

if [[ ${array[$test1]} ]]; then echo "Exists"; fi    # Exists
if [[ ${array[$test2]} ]]; then echo "Exists"; fi    # doesn't

для того, чтобы настроить массив первоначально вы могли бы также делать прямые назначения:

array[foo]=1
array[bar]=1
# etc.

или так:

array=([foo]=1 [bar]=1 [baz]=1)
21
отвечен Dennis Williamson 2023-01-16 18:16

Это старый вопрос, но я думаю, что самое простое решение еще не появилось:test ${array[key]+_}. Пример:

declare -A xs=([a]=1 [b]="")
test ${xs[a]+_} && echo "a is set"
test ${xs[b]+_} && echo "b is set"
test ${xs[c]+_} && echo "c is set"

выходы:

a is set
b is set

чтобы увидеть, как это работает проверить этой.

8
отвечен tokland 2023-01-16 20:33

есть способ проверить, существует ли элемент ассоциативного массива (не задан), это отличается от empty:

isNotSet() {
    if [[ ! ${!1} && ${!1-_} ]]
    then
        return 1
    fi
}

затем использовать его:

declare -A assoc
KEY="key"
isNotSet assoc[${KEY}]
if [ $? -ne 0 ]
then
  echo "${KEY} is not set."
fi
5
отвечен Diego F. Durán 2023-01-16 22:50

вы можете видеть, присутствует ли запись, передавая содержимое массива в grep.

 printf "%s\n" "${mydata[@]}" | grep "^${val}$"

вы также можете получить индекс записи с помощью grep-n, который возвращает номер строки соответствия (не забудьте вычесть 1, чтобы получить индекс на основе нуля) Это будет достаточно быстро, за исключением очень больших массивов.

# given the following data
mydata=(a b c "hello world")

for val in a c hello "hello world"
do
           # get line # of 1st matching entry
    ix=$( printf "%s\n" "${mydata[@]}" | grep -n -m 1 "^${val}$" | cut -d ":" -f1 )

    if [[ -z $ix ]]
    then
        echo $val missing
    else
         # subtract 1.  Bash arrays are zero-based, but grep -n returns 1 for 1st line, not 0 
        echo $val found at $(( ix-1 ))
    fi
done

a found at 0
c found at 2
hello missing
hello world found at 3

объяснение:

  • $( ... ) это то же самое, что использовать обратные ссылки для захвата вывода команды в переменную
  • printf выводит mydata один элемент на строку
  • (все необходимые кавычки вместе с @ вместо *. это позволяет избежать разделения "hello world" на 2 строки)
  • grep поиск точной строки:^ и $ матч начало и конец строки
  • grep -n возвращает строку #, в виде 4: hello world
  • grep -m 1 находит только первый матч
  • cut извлекает только номер строки
  • вычесть 1 из возвращаемого номера строки.

вы конечно можете сложить вычитание в команду. Но тогда тест на -1 пропущен:

ix=$(( $( printf "%s\n" "${mydata[@]}" | grep -n -m 1 "^${val}$" | cut -d ":" -f1 ) - 1 ))

if [[ $ix == -1 ]]; then echo missing; else ... fi
  • $(( ... )) не целочисленная арифметика
3
отвечен kane 2023-01-17 01:07

Я не думаю, что вы можете сделать это правильно без цикла, если у вас есть очень ограниченные данные в массиве.

вот один простой вариант, это бы правильно сказать, что "Super User" существует в массиве. Но было бы также сказать, что "uper Use" в массиве.

MyArray=('Super User' 'Stack Overflow' 'Server Fault' 'Jeff' );
FINDME="Super User"

FOUND=`echo ${MyArray[*]} | grep "$FINDME"`

if [ "${FOUND}" != "" ]; then
  echo Array contains: $FINDME
else
  echo $FINDME not found
fi

#
# If you where to add anchors < and > to the data it could work
# This would find "Super User" but not "uper Use"
#

MyArray2=('<Super User>' '<Stack Overflow>' '<Server Fault>' '<Jeff>' );

FOUND=`echo ${MyArray2[*]} | grep "<$FINDME>"`

if [ "${FOUND}" != "" ]; then
  echo Array contains: $FINDME
else
  echo $FINDME not found
fi

проблема в том, что нет простого способа добавить якоря (о котором я могу думать), кроме цикла через массив. Если вы не можете добавить их, прежде чем поместить их в массив...

1
отвечен Nifle 2023-01-17 03:24
#!/bin/bash
function in_array {
  ARRAY=
  for e in ${ARRAY[*]}
  do
    if [[ "$e" == "" ]]
    then
      return 0
    fi
  done
  return 1
}

my_array=(Drupal Wordpress Joomla)
if in_array "Drupal" "${my_array[*]}"
  then
    echo "Found"
  else
    echo "Not found"
fi
1
отвечен Cong Nguyen 2023-01-17 05:41

Постоянная ссылка на данную страницу: [ Скопировать ссылку | Сгенерировать QR-код ]

Ваш ответ

Опубликуйте как Гость или авторизуйтесь

Имя
Вверх