J'essaie d'écrire un script en bash qui vérifie la validité d'une entrée utilisateur.
Je veux faire correspondre l'entrée (disons la variable x
) à une liste de valeurs valides.
ce que je suis venu avec pour le moment est:
for item in $list
do
if [ "$x" == "$item" ]; then
echo "In the list"
exit
fi
done
Ma question est de savoir s'il existe un moyen plus simple de le faire,
quelque chose comme une list.contains(x)
pour la plupart des langages de programmation.
Une addition:
Dites que la liste est:
list="11 22 33"
mon code fera écho au message uniquement pour ces valeurs car list
est traité comme un tableau et non une chaîne, toutes les manipulations de chaîne valideront 1
alors que je voudrais qu'il échoue.
[[ $list =~ (^|[[:space:]])$x($|[[:space:]]) ]] && echo 'yes' || echo 'no'
ou créer une fonction:
contains() {
[[ $1 =~ (^|[[:space:]])$2($|[[:space:]]) ]] && exit(0) || exit(1)
}
pour l'utiliser:
contains aList anItem
echo $? # 0: match, 1: failed
Matvey a raison, mais vous devriez citer $ x et envisager tout type "d'espaces" (par exemple, une nouvelle ligne) avec
[[ $list =~ (^|[[:space:]])"$x"($|[[:space:]]) ]] && echo 'yes' || echo 'no'
donc, c'est-à-dire.
# 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
}
fin ensuite
`list_include_item "10 11 12" "12"` && echo "yes" || echo "no"
ou
if `list_include_item "10 11 12" "1"` ; then
echo "yes"
else
echo "no"
fi
Notez que vous devez utiliser ""
dans le cas de variables:
`list_include_item "$my_list" "$my_item"` && echo "yes" || echo "no"
Vous pouvez également utiliser (* caractères génériques) en dehors d'une instruction case si vous utilisez des crochets doubles:
string='My string';
if [[ $string == *My* ]]
then
echo "It's there!";
fi
IMHO solution la plus simple consiste à ajouter et ajouter la chaîne originale avec un espace et vérifier par rapport à une regex avec [[ ]]
haystack='foo bar'
needle='bar'
if [[ " $haystack " =~ .*\ $needle\ .* ]]; then
...
fi
cela ne sera pas faux positif sur les valeurs avec des valeurs contenant l'aiguille en tant que sous-chaîne, par ex. avec une botte de foin foo barbaz
.
(Le concept est volé sans vergogne de la méthode hasClass()
- de la méthode JQuery)
que diriez-vous
echo $list|grep $x
vous pouvez vérifier la sortie ou $?
de la ligne ci-dessus pour prendre la décision.
Si la liste est corrigée dans le script, j'aime le mieux ce qui suit:
validate() {
grep -F -q -x "$1" <<EOF
item 1
item 2
item 3
EOF
}
Utilisez ensuite validate "$x"
pour vérifier si $x
est autorisé.
Si vous voulez une ligne, sans vous soucier des espaces dans les noms d'éléments, vous pouvez utiliser ceci (notez -w
au lieu de -x
):
validate() { echo "11 22 33" | grep -F -q -w "$1"; }
Remarques:
sh
.validate
fait pas accepte des sous-chaînes (supprimez l’option -x
de grep si vous le souhaitez).validate
interprète son argument comme une chaîne fixe, pas comme une expression régulière .__ (supprimez l'option -F
de grep si vous le souhaitez).Exemple de code pour exercer la fonction:
for x in "item 1" "item2" "item 3" "3" "*"; do
echo -n "'$x' is "
validate "$x" && echo "valid" || echo "invalid"
done
Je trouve qu'il est plus facile d'utiliser le formulaire echo $LIST | xargs -n1 echo | grep $VALUE
comme illustré ci-dessous:
LIST="ITEM1 ITEM2"
VALUE="ITEM1"
if [ -n "`echo $LIST | xargs -n1 echo | grep -e \"^$VALUE`$\" ]; then
...
fi
Cela fonctionne pour une liste séparée par des espaces, mais vous pouvez l'adapter à tout autre délimiteur (comme :
) en procédant comme suit:
LIST="ITEM1:ITEM2"
VALUE="ITEM1"
if [ -n "`echo $LIST | sed 's|:|\\n|g' | grep -e \"^$VALUE`$\"`" ]; then
...
fi
Notez que les "
sont requis pour que le test fonctionne.
Envisagez d'exploiter les clés de tableaux associatifs . Je présume que cela surpasse à la fois la correspondance regex/pattern et les boucles, bien que je ne l’aie pas encore profilé.
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
Sortie:
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 )
Si votre liste de valeurs doit être codée en dur dans le script, il est relativement simple de tester avec case
. Voici un court exemple que vous pouvez adapter à vos besoins:
for item in $list
do
case "$x" in
item1|item2)
echo "In the list"
;;
not_an_item)
echo "Error" >&2
exit 1
;;
esac
done
Si la liste est une variable de tableau au moment de l'exécution, l'une des autres réponses est probablement plus appropriée.
$ 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
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 "$@"
do
if [ "$SEARCH_FOR" == "$ITEM" ]
then
echo "YES"
exit;
fi
done
echo "NO"
En supposant que la variable TARGET ne peut être que 'binomiale' ou 'régression', voici ce que vous ferez:
# 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
Vous pouvez ajouter plus de chaînes dans la liste en les séparant par un | caractère (pipe).
Avec egrep, vous pouvez facilement ajouter une insensibilité à la casse (-i) ou vérifier des scénarios plus complexes avec une expression régulière.
C'est presque votre proposition initiale, mais presque une ligne. Pas si compliqué que d’autres réponses valables, et pas du tout dépendant des versions de bash (peut fonctionner avec d’anciens 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 ; }
Je suppose que ma proposition peut encore être améliorée, à la fois en longueur et en style.
Je pensais ajouter ma solution à la liste.
# 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