Как проверить, существует ли переменная в списке в BASH
Я пытаюсь написать script в bash, который проверяет правильность ввода пользователя.
Я хочу совместить вход (например, переменную x
) со списком допустимых значений.
то, что я придумал в данный момент:
for item in $list
do
if [ "$x" == "$item" ]; then
echo "In the list"
exit
fi
done
Мой вопрос в том, есть ли более простой способ сделать это,
что-то вроде list.contains(x)
для большинства языков программирования.
Дополнение:
Список слов:
list="11 22 33"
мой код будет эхо-сообщение только для этих значений, так как list
рассматривается как массив, а не строка,
все манипуляции с строкой будут проверять 1
, пока я хочу, чтобы он потерпел неудачу.
Ответы
Ответ 1
[[ $list =~ (^|[[:space:]])$x($|[[:space:]]) ]] && echo 'yes' || echo 'no'
или создать функцию:
contains() {
[[ $1 =~ (^|[[:space:]])$2($|[[:space:]]) ]] && exit(0) || exit(1)
}
чтобы использовать его:
contains aList anItem
echo $? # 0: match, 1: failed
Ответ 2
Матвей прав, но вы должны цитировать $x и рассматривать любые "пробелы" (например, новую строку) с помощью
[[ $list =~ (^|[[:space:]])"$x"($|[[:space:]]) ]] && echo 'yes' || echo 'no'
так, то есть
# list_include_item "10 11 12" "2"
function list_include_item {
local list="$1"
local item="$2"
if [[ $list =~ (^|[[:space:]])"$item"($|[[:space:]]) ]] ; then
# yes, list include item
result=0
else
result=1
fi
return $result
}
end then
`list_include_item "10 11 12" "12"` && echo "yes" || echo "no"
или
if `list_include_item "10 11 12" "1"` ; then
echo "yes"
else
echo "no"
fi
Обратите внимание, что вы должны использовать ""
в случае переменных:
`list_include_item "$my_list" "$my_item"` && echo "yes" || echo "no"
Ответ 3
Вы можете использовать (* подстановочные знаки) за пределами оператора case, если вы используете двойные скобки:
string='My string';
if [[ $string == *My* ]]
then
echo "It there!";
fi
Ответ 4
Самое простое решение IMHO состоит в том, чтобы добавить и добавить исходную строку с пробелом и проверить регулярное выражение с помощью [[ ]]
haystack='foo bar'
needle='bar'
if [[ " $haystack " =~ .*\ $needle\ .* ]]; then
...
fi
это не будет ложным положительным для значений со значениями, содержащими иглу в качестве подстроки, например. с haystack foo barbaz
.
(Концепция бесстыдно украдена в форме JQuery hasClass()
-Method)
Ответ 5
как насчет
echo $list|grep $x
вы можете проверить выход или $?
указанной выше строки, чтобы принять решение.
Ответ 6
Мне легче использовать форму echo $LIST | xargs -n1 echo | grep $VALUE
, как показано ниже:
LIST="ITEM1 ITEM2"
VALUE="ITEM1"
if [ -n "`echo $LIST | xargs -n1 echo | grep -e \"^$VALUE`$\" ]; then
...
fi
Это работает для списка, разделенного пробелами, но вы можете адаптировать его к любому другому разделителю (например, :
), выполнив следующие действия:
LIST="ITEM1:ITEM2"
VALUE="ITEM1"
if [ -n "`echo $LIST | sed 's|:|\\n|g' | grep -e \"^$VALUE`$\"`" ]; then
...
fi
Обратите внимание, что для тестирования необходимо < <24 > .
Ответ 7
Рассмотрим использование ключей ассоциативных массивов. Я бы предположил, что это превосходит как соответствие регулярному выражению/шаблону, так и цикл, хотя я не профилировал его.
declare -A list=( [one]=1 [two]=two [three]='any non-empty value' )
for value in one two three four
do
echo -n "$value is "
# a missing key expands to the null string,
# and we've set each interesting key to a non-empty value
[[ -z "${list[$value]}" ]] && echo -n '*not* '
echo "a member of ( ${!list[*]} )"
done
Вывод:
one is a member of ( one two three )
two is a member of ( one two three )
three is a member of ( one two three )
four is *not* a member of ( one two three )
Ответ 8
Если список зафиксирован в script, мне нравится следующее:
validate() {
grep -F -q -x "$1" <<EOF
item 1
item 2
item 3
EOF
}
Затем используйте validate "$x"
, чтобы проверить, разрешено ли $x
.
Если вы хотите использовать однострочный шрифт и не интересуетесь пробелами в именах элементов, вы можете использовать это (обратите внимание -w
вместо -x
):
validate() { echo "11 22 33" | grep -F -q -w "$1"; }
Примечания:
- Это соответствует POSIX
sh
.
-
validate
не принимает подстроки (удалите параметр -x
для grep, если вы этого хотите).
-
validate
интерпретирует свой аргумент как фиксированную строку, а не регулярную
выражение (удалите параметр -F
для grep, если вы этого хотите).
Пример кода для выполнения функции:
for x in "item 1" "item2" "item 3" "3" "*"; do
echo -n "'$x' is "
validate "$x" && echo "valid" || echo "invalid"
done
Ответ 9
Если ваш список значений должен быть жестко закодирован в script, его довольно просто проверить с помощью case
. Вот краткий пример, который вы можете адаптировать к своим требованиям:
for item in $list
do
case "$x" in
item1|item2)
echo "In the list"
;;
not_an_item)
echo "Error" >&2
exit 1
;;
esac
done
Если список является переменной массива во время выполнения, один из других ответов, вероятно, лучше подходит.
Ответ 10
Примеры
$ in_list super test me out
NO
$ in_list "super dude" test me out
NO
$ in_list "super dude" test me "super dude"
YES
# How to use in another script
if [ $(in_list $1 OPTION1 OPTION2) == "NO" ]
then
echo "UNKNOWN type for param 1: Should be OPTION1 or OPTION2"
exit;
fi
in_list
function show_help()
{
IT=$(CAT <<EOF
usage: SEARCH_FOR {ITEM1} {ITEM2} {ITEM3} ...
e.g.
a b c d -> NO
a b a d -> YES
"test me" how "test me" -> YES
)
echo "$IT"
exit
}
if [ "$1" == "help" ]
then
show_help
fi
if [ "$#" -eq 0 ]; then
show_help
fi
SEARCH_FOR=$1
shift;
for ITEM in "[email protected]"
do
if [ "$SEARCH_FOR" == "$ITEM" ]
then
echo "YES"
exit;
fi
done
echo "NO"
Ответ 11
Предполагая, что переменная TARGET может быть только "биномиальной" или "регрессией", тогда следующее:
# Check for modeling types known to this script
if [ $( echo "${TARGET}" | egrep -c "^(binomial|regression)$" ) -eq 0 ]; then
echo "This scoring program can only handle 'binomial' and 'regression' methods now." >&2
usage
fi
Вы можете добавить больше строк в список, разделив их на | (трубе).
Преимущество использования egrep заключается в том, что вы можете легко добавить нечувствительность к регистру (-i) или проверить более сложные сценарии с регулярным выражением.
Ответ 12
Думал, что добавлю свое решение в список.
# Checks if element "$1" is in array "$2"
# @NOTE:
# Be sure that array is passed in the form:
# "${ARR[@]}"
elementIn () {
# shopt -s nocasematch # Can be useful to disable case-matching
local e
for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done
return 1
}
# Usage:
list=(11 22 33)
item=22
if elementIn "$item" "${list[@]}"; then
echo TRUE;
else
echo FALSE
fi
# TRUE
item=44
elementIn $item "${list[@]}" && echo TRUE || echo FALSE
# FALSE
Ответ 13
Это почти ваше первоначальное предложение, но почти 1-лайнер. Не так сложно, как другие действительные ответы, и не так зависит от версий bash (может работать со старыми bashes).
OK=0 ; MP_FLAVOURS="vanilla lemon hazelnut straciatella"
for FLAV in $MP_FLAVOURS ; do [ $FLAV == $FLAVOR ] && { OK=1 ; break; } ; done
[ $OK -eq 0 ] && { echo "$FLAVOR not a valid value ($MP_FLAVOURS)" ; exit 1 ; }
Думаю, мое предложение все еще может быть улучшено как по длине, так и по стилю.