206 votes

Vérifier si une variable existe dans une liste en Bash

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 j'ai trouvé pour l'instant, c'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 procéder,
quelque chose comme un list.contains(x) pour la plupart des langages de programmation.

Dites la liste :

list="11 22 33"

mon code n'affichera le message que pour ces valeurs puisque list est traité comme un tableau et non comme une chaîne de caractères, toutes les manipulations de chaînes de caractères seront validées 1 alors que je voudrais qu'il échoue.

8voto

glenn jackman Points 69748

Puisque vous validez l'entrée de l'utilisateur, je ne ferais pas confiance à l'utilisateur pour éviter de saisir une chaîne exempte de la syntaxe des expressions régulières. Je m'en tiendrais à la méthode for l'approche en boucle.

listcontains() {
  for word in $1; do
    [[ $word = $2 ]] && return 0
  done
  return 1
}
list="11 22 33"
if listcontains "$list" 1; then echo Y; else echo N; fi
if listcontains "$list" 22; then echo Y; else echo N; fi

6voto

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 à 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

Il convient de noter que le " sont nécessaires pour que le test fonctionne.

5voto

SamWN Points 338

J'ai pensé 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

5voto

Qub3r Points 49

Le compgen intégré à l'interpréteur de commandes peut vous aider à cet égard. Il peut prendre une liste avec l'option -W et renvoyer toutes les correspondances potentielles qu'il trouve.

# My list can contain spaces so I want to set the internal
# file separator to newline to preserve the original strings.
IFS=$'\n'

# Create a list of acceptable strings.
accept=( 'foo' 'bar' 'foo bar' )

# The string we will check
word='foo'

# compgen will return a list of possible matches of the 
# variable 'word' with the best match being first.
compgen -W "${accept[*]}" "$word"

# Returns:
# foo
# foo bar

Nous pouvons écrire une fonction pour tester si une chaîne est égale à la meilleure correspondance de chaînes acceptables. Cela vous permet de renvoyer un 0 ou un 1 pour une réussite ou un échec respectivement.

function validate {
  local IFS=$'\n'
  local accept=( 'foo' 'bar' 'foo bar' )
  if [ "$1" == "$(compgen -W "${accept[*]}" "$1" | head -1)" ] ; then
    return 0
  else
    return 1
  fi
}

Vous pouvez maintenant écrire des tests très propres pour valider si une chaîne de caractères est acceptable.

validate "blah" || echo unacceptable

if validate "foo" ; then
  echo acceptable
else 
  echo unacceptable
fi

4voto

A-B-B Points 797

Les réponses précédentes n'utilisent pas tr que j'ai trouvée utile avec grep . En supposant que les éléments de la liste sont délimités par des espaces, pour vérifier une correspondance exacte :

echo $mylist | tr ' ' '\n' | grep -F -x -q "$myitem"

Cette opération renvoie le code de sortie 0 si l'élément se trouve dans la liste, ou le code de sortie 1 s'il ne s'y trouve pas.

Il est préférable de l'utiliser comme une fonction :

_contains () {  # Check if space-separated list $1 contains line $2
  echo "$1" | tr ' ' '\n' | grep -F -x -q "$2"
}

mylist="aa bb cc"

# Positive check
if _contains "${mylist}" "${myitem}"; then
  echo "in list"
fi

# Negative check
if ! _contains "${mylist}" "${myitem}"; then
  echo "not in list"
fi

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X