Comment vérifier si une variable existe dans une liste dans BASH
J'essaie d'écrire un script dans bash qui vérifie la validité d'une entrée utilisateur.
Je veux correspondre à l'entrée (disons variable x
) à une liste de valeurs valides.
Ce que j'ai en ce 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 un list.contains(x)
pour la plupart des langages de programmation.
Plus:
Dites liste est:
list="11 22 33"
Mon code fera écho au message uniquement pour ces valeurs puisque 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.
11 réponses
[[ $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 considérer tout type d '"espaces" (par exemple 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 puis
`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 ""
en cas de variables:
`list_include_item "$my_list" "$my_item"` && echo "yes" || echo "no"
Vous pouvez également utiliser (*wildcards) en dehors d'une instruction case, si vous utilisez des crochets doubles:
string='My string';
if [[ $string == *My* ]]
then
echo "It's there!";
fi
Que diriez-vous de
echo $list|grep $x
, Vous pouvez soit cocher la sortie ou $?
de la ligne ci-dessus pour prendre la décision.
La solution la plus simple à mon humble avis est d'ajouter et d'ajouter la chaîne d'origine avec un espace et de vérifier une expression rationnelle avec [[ ]]
haystack='foo bar'
needle='bar'
if [[ " $haystack " =~ .*\ $needle\ .* ]]; then
...
fi
Ce ne sera pas faux positif sur les valeurs avec des valeurs contenant l'aiguille comme sous-chaîne, par exemple avec une botte de foin foo barbaz
.
(le concept est volé sans vergogne sous la forme hasClass()
-Méthode de JQuery)
Je trouve que c'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 à n'importe quel 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 nécessaires pour que le test fonctionne.
Si votre liste de valeurs doit être codée en dur dans le script, il est assez simple de tester en utilisant case
. Voici un petit 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 à l'exécution, l'une des autres réponses est probablement un meilleur ajustement.
Envisagez d'exploiter les clés de tableaux associatifs. Je suppose que cela surpasse à la fois la correspondance regex/pattern et la boucle, bien que je ne l'ai pas 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 la liste est fixée dans le script, j'aime ce qui suit le mieux:
validate() {
grep -F -q -x "$1" <<EOF
item 1
item 2
item 3
EOF
}
, Puis utilisez validate "$x"
pour tester si $x
est autorisé.
Si vous voulez un one-liner, et ne vous souciez pas des espaces dans les noms d'éléments, vous pouvez utiliser ceci (notice -w
au lieu de -x
):
validate() { echo "11 22 33" | grep -F -q -w "$1"; }
Notes:
- ceci est conforme à POSIX
sh
. -
validate
n'accepte pas les sous-chaînes (supprimez l'option-x
pour grep si vous le souhaitez). -
validate
interprète son argument comme une chaîne fixe, pas un expression (supprimez l'option-F
pour 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
Exemples
$ 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 "$@"
do
if [ "$SEARCH_FOR" == "$ITEM" ]
then
echo "YES"
exit;
fi
done
echo "NO"
En supposant que la variable cible ne peut être que "binomiale" ou "régression", alors suivre ferait:
# 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 avec un caractère / (pipe).
L'avantage d'utiliser egrep, c'est que vous pouvez facilement ajouter l'insensibilité à la casse (-i), ou vérifier des scénarios plus complexes avec une expression régulière.