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

5voto

Dennis Williamson Points 105818

Vous pouvez supprimer les chiffres qui n'en sont pas et faire une comparaison. Voici une démonstration script :

for num in "44" "-44" "44-" "4-4" "a4" "4a" ".4" "4.4" "-4.4" "09"
do
    match=${num//[^[:digit:]]}    # strip non-digits
    match=${match#0*}             # strip leading zeros
    echo -en "$num\t$match\t"
    case $num in
        $match|-$match)    echo "Integer";;
                     *)    echo "Not integer";;
    esac
done

Voici à quoi ressemble le résultat du test :

44      44      Integer
-44     44      Integer
44-     44      Not integer
4-4     44      Not integer
a4      4       Not integer
4a      4       Not integer
.4      4       Not integer
4.4     44      Not integer
-4.4    44      Not integer
09      9       Not integer

5voto

hans Points 29

Voici une autre façon de procéder (en utilisant uniquement la commande intégrée test et son code de retour) :

function is_int() { test "$@" -eq "$@" 2> /dev/null; } 

input="-123"

if is_int "$input"
then
   echo "Input: ${input}"
   echo "Integer: ${input}"
else
   echo "Not an integer: ${input}"
fi

3voto

Trebor Rude Points 417

Pour moi, la solution la plus simple était d'utiliser la variable à l'intérieur d'un fichier (()) expression, ainsi :

if ((VAR > 0))
then
  echo "$VAR is a positive integer."
fi

Bien entendu, cette solution n'est valable que si une valeur de zéro n'a pas de sens pour votre application. C'est ce qui s'est passé dans mon cas, et cette solution est beaucoup plus simple que les autres.

Comme indiqué dans les commentaires, cela peut vous exposer à une attaque par exécution de code : Le (( )) évalue VAR , comme indiqué dans le Arithmetic Evaluation section de la page de manuel bash(1) . Par conséquent, vous ne devez pas utiliser cette technique lorsque la source du contenu du fichier VAR est incertaine (et vous ne devez utiliser AUCUNE autre forme d'expansion variable, bien entendu).

1voto

knipwim Points 21

Ou avec sed :

   test -z $(echo "2000" | sed s/[0-9]//g) && echo "integer" || echo "no integer"
   # integer

   test -z $(echo "ab12" | sed s/[0-9]//g) && echo "integer" || echo "no integer"
   # no integer

0voto

JustinMT Points 13

Complément de réponse de Ignacio Vazquez-Abrams. Cela permettra au signe + de précéder l'entier, et autorisera n'importe quel nombre de zéros comme points décimaux. Par exemple, +45.00000000 peut être considéré comme un entier.
Cependant, $1 doit être formaté pour contenir un point décimal. Ici, 45 n'est pas considéré comme un entier, mais 45.0 l'est.

if [[ $1 =~ ^-?[0-9]+.?[0]+$ ]]; then
    echo "yes, this is an integer"
elif [[ $1 =~ ^\+?[0-9]+.?[0]+$ ]]; then
    echo "yes, this is an integer"
else
    echo "no, this is not an integer"
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