Есть хороший способ проверить, есть ли в массиве элемент в bash (лучше, чем циклически проходить)?
В качестве альтернативы, есть ли другой способ проверить, равно ли число или строка какой-либо из набора предопределенных констант?
Есть хороший способ проверить, есть ли в массиве элемент в bash (лучше, чем циклически проходить)?
В качестве альтернативы, есть ли другой способ проверить, равно ли число или строка какой-либо из набора предопределенных констант?
В 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 [[ $ ]]; then echo "Exists"; fi # Exists if [[ $ ]]; then echo "Exists"; fi # doesn't Для первоначальной настройки массива вы также можете выполнить прямые назначения:
array[foo]=1 array[bar]=1 # etc. или так:
array=([foo]=1 [bar]=1 [baz]=1) $ прост, но имеет проблему: он не будет работать, если вы будете использовать set -u в своих скриптах (что рекомендуется), так как вы получите" несвязанную переменную ".
@tokland: кто это рекомендует? Я конечно не
@DennisWilliamson: Хорошо, * некоторые люди * рекомендуют это, но я думаю, что было бы неплохо иметь решение, которое работает независимо от значения этих флагов.
Некоторые сообщения о set -u: http://www.davidpashley.com/articles/writing-robust-shell-scripts.html, http://blog.hashbang0.com/2010/05/18/robust-bash -scripts-part-one /, http://www.openews.net/2012/bash-script-to-write-robust/.
Это старый вопрос, но я думаю, что самое простое решение еще не появилось test $. Пример:
declare -A xs=([a]=1 [b]="") test $ && echo "a is set" test $ && echo "b is set" test $ && echo "c is set" Выходы:
a is set b is set Чтобы увидеть, как это работает, проверьте это .
Информационное руководство рекомендует вам использовать env, чтобы избежать двусмысленности в псевдонимах, прогах и других функциях, которые могли принять название« тест ». Как указано выше, env test $ && echo" a is set ". Вы также можете получить эту функциональность, используя двойные скобки, тот же трюк с проверкой на нуль: [[! -z "$ "]] && echo "b установлено"
Есть способ проверить, существует ли элемент ассоциативного массива (не установлен), это отличается от пустого:
isNotSet() { if [[ ! ${!1} && ${!1-_} ]] then return 1 fi } Тогда используйте это:
declare -A assoc KEY="key" isNotSet assoc[$] if [ $? -ne 0 ] then echo "$ is not set." fi Примечание: -A не работает на bash 3.2.39 (debian lenny), но работает на bash 4.1.5 (debian squeeze)
Ассоциативные массивы были введены в Bash 4.
обратите внимание, что если! some_check затем возвращает 1 = some_check. Итак: isNotSet () {[[...]]}. Проверьте мое решение ниже, вы можете сделать это в простой проверке.
You can see if an entry is present by piping the contents of the array to grep.
printf "%s\n" "$" | grep "^$$" You can also get the index of an entry with grep -n, which returns the line number of a match (remember to subtract 1 to get zero-based index) This will be reasonably quick except for very large arrays.
# 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" "$" | grep -n -m 1 "^$$" | 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 explanation:
$( ... ) is the same as using backticks to capture output of a command into a variable printf outputs mydata one element per line @ instead of *. this avoids splitting "hello world" into 2 lines) grep searches for exact string: ^ and $ match beginning and end of line grep -n returns line #, in form of 4:hello world grep -m 1 finds first match onlycut extracts just the line number You can of course fold the subtraction into the command. But then test for -1 for missing:
ix=$(( $( printf "%s\n" "$" | grep -n -m 1 "^$$" | cut -d ":" -f1 ) - 1 )) if [[ $ix == -1 ]]; then echo missing; else ... fi $(( ... )) does integer arithmeticЯ не думаю, что вы можете сделать это правильно без циклов, если у вас нет очень ограниченных данных в массиве.
Вот один простой вариант, это правильно сказал бы, что "Super User"существует в массиве. Но это также сказал бы, что "uper Use"находится в массиве.
MyArray=('Super User' 'Stack Overflow' 'Server Fault' 'Jeff' ); FINDME="Super User" FOUND=`echo $ | grep "$FINDME"` if [ "$" != "" ]; 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 $ | grep "<$FINDME>"` if [ "$" != "" ]; then echo Array contains: $FINDME else echo $FINDME not found fi Проблема в том, что нет простого способа добавить якоря (о которых я могу думать), кроме циклического перемещения по массиву. Если вы не можете добавить их, прежде чем поместить их в массив ...
Это хорошее решение, когда константы буквенно-цифровые, хотя (с grep" \ b $ FINDME \ b "). Вероятно, может работать с не алфавитно-цифровыми константами, которые не имеют пробелов, с " (^ |) $ FINDME (\ $ |) " (или что-то в этом роде ... Мне никогда не удавалось узнать, какой вариант использования regexp grep использует .)
#!/bin/bash function in_array { ARRAY=$2 for e in $ do if [[ "$e" == "$1" ]] then return 0 fi done return 1 } my_array=(Drupal Wordpress Joomla) if in_array "Drupal" "$" then echo "Found" else echo "Not found" fi Можете ли вы уточнить, почему вы предлагаете этот подход? OP спросил, есть ли способ сделать это * без циклического перебора массива *, что вы и делаете в in_array. ура
Ну, по крайней мере, этот цикл заключен в функцию, что может быть достаточно для многих случаев (с небольшими наборами данных) и не требует bash 4+. Вероятно, следует использовать $ .
Ctrl+K или / — быстрый поиск Начните вводить запрос для поиска по сайту
На самом деле, тест [[]] не работает, если значение пустое. Например, "array ['test'] = ''". В этом случае ключ 'test' существует, и вы можете увидеть его в списке с $ {! Array [@]}, но "[[$ ]]; echo $?" Отголоски 1, а не 0.