140 votes

Tester si la chaîne est un entier valide

J'essaie de faire quelque chose d'assez commun : Analyser l'entrée utilisateur dans un shell script. Si l'utilisateur a fourni un entier valide, le script fait une chose, et s'il n'est pas valide, il fait autre chose. Le problème est que je n'ai pas trouvé de moyen facile (et raisonnablement élégant) de faire cela - je ne veux pas avoir à le décortiquer caractère par caractère.

Je sais que cela doit être facile, mais je ne sais pas comment. Je pourrais le faire dans une douzaine de langues, mais pas en BASH !

Dans mes recherches, j'ai trouvé ceci :

Expression régulière permettant de vérifier si une chaîne de caractères est constituée d'un nombre réel valide en base 10

Et il y a une réponse qui parle de regex, mais pour autant que je sache, c'est une fonction disponible en C (entre autres). Néanmoins, il y avait ce qui semblait être une bonne réponse, alors j'ai essayé avec grep, mais grep ne savait pas quoi en faire. J'ai essayé -P qui, sur ma machine, signifie qu'il faut le traiter comme un regexp PERL - rien. Dash E (-E) n'a pas fonctionné non plus. Et -F non plus.

Pour être clair, j'essaie quelque chose comme ça, à la recherche d'un résultat - à partir de là, je modifierai le script pour tirer parti de ce que j'obtiendrai. (En d'autres termes, je m'attendais à ce qu'une entrée non conforme ne renvoie rien alors qu'une ligne valide est répétée).

snafu=$(echo "$2" | grep -E "/^[-+]?(?:\.[0-9]+|(?:0|[1-9][0-9]*)(?:\.[0-9]*)?)$/")
if [ -z "$snafu" ] ;
then
   echo "Not an integer - nothing back from the grep"
else
   echo "Integer."
fi

Quelqu'un pourrait-il illustrer la manière la plus simple de procéder ?

Franchement, c'est un défaut de TEST, à mon avis. Il devrait avoir un drapeau comme celui-ci

if [ -I "string" ] ;
then
   echo "String is a valid integer."
else
   echo "String is not a valid integer."
fi

210voto

Ignacio Vazquez-Abrams Points 312628
[[ $var =~ ^-?[0-9]+$ ]]
  • En ^ indique le début du motif d'entrée
  • En - est un "-" littéral
  • En ? signifie "0 ou 1 des éléments précédents ( - )"
  • En + signifie "1 ou plusieurs des ( [0-9] )"
  • En $ indique la fin du modèle d'entrée

L'expression rationnelle correspond donc à un élément facultatif - (pour les nombres négatifs), suivi d'un ou plusieurs chiffres décimaux.

Références :

76voto

Peter Ho Points 49

Wow... il y a tellement de bonnes solutions ici ! De toutes les solutions ci-dessus, je suis d'accord avec @nortally pour dire que l'utilisation de la fonction -eq L'étiquette est la plus cool qui soit.

J'utilise GNU bash, version 4.1.5 (Debian). J'ai également vérifié avec ksh (SunSO 5.10).

Voici ma version de la vérification de l'existence de $1 est un entier ou non :

if [ "$1" -eq "$1" ] 2>/dev/null
then
    echo "$1 is an integer !!"
else
    echo "ERROR: first parameter must be an integer."
    echo $USAGE
    exit 1
fi

Cette approche prend également en compte les nombres négatifs, alors que certaines des autres solutions donnent un résultat négatif erroné, et permet d'utiliser le préfixe "+" (par exemple, +30), qui est évidemment un nombre entier.

Résultats :

$ int_check.sh 123
123 is an integer !!

$ int_check.sh 123+
ERROR: first parameter must be an integer.

$ int_check.sh -123
-123 is an integer !!

$ int_check.sh +30
+30 is an integer !!

$ int_check.sh -123c
ERROR: first parameter must be an integer.

$ int_check.sh 123c
ERROR: first parameter must be an integer.

$ int_check.sh c123
ERROR: first parameter must be an integer.

La solution fournie par Ignacio Vazquez-Abrams était également très soignée (si vous aimez les regex) après avoir été expliquée. Cependant, elle ne gère pas les nombres positifs avec la fonction + mais il peut facilement être corrigé comme suit :

[[ $var =~ ^[-+]?[0-9]+$ ]]

43voto

tripleee Points 28746

Je suis arrivé tardivement à la fête. Je suis extrêmement surpris qu'aucune des réponses ne mentionne la solution la plus simple, la plus rapide et la plus portable : le case déclaration.

case ${variable#[-+]} in
  *[!0-9]* | '') echo Not a number ;;
  * ) echo Valid number ;;
esac

L'élimination de tout signe avant la comparaison semble être un peu un piratage, mais cela rend l'expression de la déclaration de cas tellement plus simple.

13voto

nortally Points 79

J'aime la solution qui consiste à utiliser le -eq parce qu'il s'agit d'une simple phrase.

Ma propre solution a été d'utiliser l'expansion des paramètres pour jeter tous les chiffres et voir s'il restait quelque chose. (J'utilise toujours la version 3.0, je n'ai pas utilisé la version [[ o expr avant, mais heureux de les rencontrer).

if [ "${INPUT_STRING//[0-9]}" = "" ]; then
  # yes, natural number
else
  # no, has non-numeral chars
fi

10voto

ephemient Points 87003

Pour la portabilité vers la version pré-Bash 3.1 (lorsque l'option =~ a été introduit), utiliser expr .

if expr "$string" : '-\?[0-9]\+$' >/dev/null
then
  echo "String is a valid integer."
else
  echo "String is not a valid integer."
fi

expr STRING : REGEX recherche les REGEX ancrés au début de STRING, en affichant le premier groupe (ou la longueur de la correspondance, s'il n'y en a pas) et en renvoyant le succès/l'échec. Il s'agit d'une ancienne syntaxe de regex, d'où l'excès de \ . -\? signifie "peut-être - ", [0-9]\+ signifie "un ou plusieurs chiffres", et $ signifie "fin de la chaîne".

Bash supporte également les globs étendus, mais je ne me souviens plus à partir de quelle version.

shopt -s extglob
case "$string" of
    @(-|)[0-9]*([0-9]))
        echo "String is a valid integer." ;;
    *)
        echo "String is not a valid integer." ;;
esac

# equivalently, [[ $string = @(-|)[0-9]*([0-9])) ]]

@(-|) signifie " - ou rien", [0-9] signifie "chiffre", et *([0-9]) signifie "zéro ou plusieurs chiffres".

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