/ bin / dash: vérifiez si $ 1 est un nombre

12

Quelle serait la meilleure façon de vérifier si $ 1 est un entier dans / bin / dash?

En bash, je pourrais faire:

[[ $1 =~ ^([0-9]+)$ ]]

Mais cela ne semble pas être conforme à POSIX et le tableau de bord ne prend pas en charge cela

Martin Vegter
la source

Réponses:

12

Les éléments suivants détectent les entiers, positifs ou négatifs, et fonctionnent sous dashet sont POSIX:

Option 1

echo "$1" | grep -Eq '^[+-]?[0-9]+$' && echo "It's an integer"

Option 2

case "${1#[+-]}" in
    ''|*[!0-9]*)
        echo "Not an integer" ;;
    *)
        echo "Integer" ;;
esac

Ou, avec un peu d'utilisation de la :commande (nop):

! case ${1#[+-]} in *[!0-9]*) :;; ?*) ! :;; esac && echo Integer
John1024
la source
5
Et si la chaîne contient des sauts de ligne? foo\n123\nbarn'est pas un entier, mais réussirait ce test.
godlygeek
3
La version grep, c'est. La version du boîtier semble correcte.
godlygeek
5

Que dash, bash, ksh, zsh, POSIX sh, ou posh( "une remise en marche de la coque Bourne" sh ); la caseconstruction est la plus largement disponible et la plus fiable:

case $1 in (*[!0-9]*|"") false ;; (*) true ;; esac
Janis
la source
Avez-vous testé cela sous dash? Cela fonctionne pour moi sous bashmais pas dash.
John1024
Oui, je l'ai également testé sur mon système avec dash; pour interroger le résultat, j'ai ajouté echo $?après la commande de cas.
Janis
J'ai fait la même chose (Debian stable) mais pas de joie. Pour un exemple complet qui fonctionne pour moi sous mon tableau de bord, voir mon option 2 .
John1024
Hmm, je n'ai pas de coque bourne d'origine à tester. Les documents que j'ai inspectés sur les "fonctionnalités [dans ksh] pas dans le bourne shell" ne le mentionnent pas du moins, donc je suppose qu'il était là. Non? - Oubliez ensuite la parenthèse principale. - OTOH, posh("une réimplémentation du shell Bourne") n'a pas non plus de problème avec cette solution.
Janis
1
@mikeserv; Il y a plusieurs raisons pour lesquelles j'utilise toujours des parenthèses correspondantes case; une raison est le bogue que vous décrivez, un autre qui, dans les éditeurs qui ont des fonctionnalités qui reposent sur des parenthèses correspondantes (vim), il offre un bien meilleur support, et non des moindres, je trouve personnellement mieux lisible de les faire correspondre. - WRT poshétant POSIX; eh bien, la citation de la page de manuel que j'ai donnée suggérait autre chose, mais on ne peut pas s'appuyer sur de telles déclarations informelles de toute façon, je suppose. Le vieux bourne shell n'est de toute façon plus aussi important maintenant que nous sommes à l'ère POSIX.
Janis
1

Vous pouvez utiliser le -eqtest sur la chaîne, avec lui-même:

$ dash -c 'a="a"; if [ "$a" -eq "$a" ] ; then echo number; else echo not a number; fi' 
dash: 1: [: Illegal number: a
not a number
$ dash -c 'a="0xa"; if [ "$a" -eq "$a" ] ; then echo number; else echo not a number; fi'
dash: 1: [: Illegal number: 0xa
not a number
$ dash -c 'a="-1"; if [ "$a" -eq "$a" ] ; then echo number; else echo not a number; fi'
number

Si le message d'erreur est un problème, redirigez la sortie d'erreur vers /dev/null:

$ dash -c 'a="0xa"; [ "$a" -eq "$a" ] 2>/dev/null|| echo no'
no
muru
la source
1
Il dirait également que " 023 "c'est un chiffre. Notez qu'il fonctionne avec dash, mais pas tous les autres shells POSIX car le comportement n'est pas spécifié si les opérandes sont des entiers décimaux de note. Par exemple avec ksh, cela dirait que SHLVLou 1+1est un nombre.
Stéphane Chazelas
0

Essayez de l'utiliser comme une expansion arithmétique et voyez si cela fonctionne. En fait, vous devez être un peu plus strict que cela, car les extensions arithmétiques ignoreraient les espaces de début et de fin, par exemple. Faites donc une expansion arithmétique et assurez-vous que le résultat développé correspond exactement à la variable d'origine.

check_if_number()
{
    if [ "$1" = "$((${1}))" ] 2>/dev/null; then
        echo "Number!"
    else
        echo "not a number"
    fi
}

Cela accepterait également les nombres négatifs - si vous voulez vraiment les exclure, ajoutez un chèque supplémentaire pour $((${1} >= 0)).

godlygeek
la source
1
le tableau de bord n'a pas[[
glenn jackman
@glennjackman Whoops. At-il $(( ... ))? Si c'est le cas, ma réponse devrait toujours être matériellement correcte, il me suffit d'ajouter quelques citations supplémentaires.
godlygeek
c'est votre réponse: allez le découvrir.
glenn jackman
Il semble que ce soit le cas, donc ma version mise à jour devrait faire l'affaire. Je n'ai pas de tableau de bord pour le tester, alors faites-moi savoir si j'ai raté autre chose.
godlygeek
J'ai essayé: check_if_number 1.2et la fonction est revenue: dash: 3: arithmetic expression: expecting EOF: "1.2"
John1024
0

Peut-être avec expr?

if expr match "$1" '^\([0-9]\+\)$' > /dev/null; then
  echo "integer"
else 
  echo "non-integer"
fi
tournevis
la source
ni matchne \+sont POSIX. Cela signifierait également que 0 n'est pas un nombre. Vous voulezexpr "x$1" : 'x[0-9]\{1,\}$'
Stéphane Chazelas
0

Dans le système POSIX, vous pouvez utiliser expr :

$ a=a
$ expr "$a" - 0 >/dev/null 2>&1
$ [ "$?" -lt 2 ] && echo Integer || echo Not Integer
cuonglm
la source
Il dira que 0 n'est pas un entier (et disons -12 est ce que la solution bash de l'OP aurait rejeté). Certaines exprimplémentations diront que 999999999999999999999 n'est pas un entier. POSIX ne donne aucune garantie que cela fonctionnera. En pratique, sur un système GNU au moins, il dira que la "longueur" est un entier.
Stéphane Chazelas
Dans mon test, cela fonctionne au moins dans Debian et OSX. Il dit entier pour 0. Posix s'assure que $ a doit être une expression valide (entier) pour expr do arithmetic.
cuonglm
Oh oui, désolé, j'avais oublié ton test pour $? <2. Toujours expr 9999999999999999999 + 0me donne un statut 3 de sortie et expr -12 + 0et expr length + 0me donner un statut de sortie 0 avec GNU expr ( + stringforces stringà considérer comme une chaîne avec GNU expr. expr "$a" - 0Fonctionnerait mieux).
Stéphane Chazelas
@ StéphaneChazelas: Oh, oui, mis à jour ma réponse. Je pense que -12c'est un entier valide, et a 9999999999999999999donné un débordement.
cuonglm
0

Voici une fonction simple utilisant la même méthode que la réponse de muru :

IsInteger()      # usage: IsInteger string
{               #  returns: flag
        [ "$1" -eq "$1" ] 2> /dev/null
}

Exemple:

p= n=2a3; IsInteger $n || p="n't" ; printf "'%s' is%s an integer\n" "$n" "$p"
p= n=23;  IsInteger $n || p="n't" ; printf "'%s' is%s an integer\n" "$n" "$p"

Production:

'2a3' isn't an integer
'23' is an integer
agc
la source