/ bin / dash: sprawdź, czy 1 $ jest liczbą

12

Jaki byłby najlepszy sposób sprawdzenia, czy 1 $ jest liczbą całkowitą w / bin / dash?

W bashu mogłem:

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

Ale to nie wydaje się być zgodne z POSIX i dash tego nie obsługuje

Martin Vegter
źródło

Odpowiedzi:

12

Następujące wykrywają liczby całkowite, dodatnie lub ujemne, i działają pod dashPOSIX i są:

opcja 1

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

Opcja 2

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

Lub przy niewielkim użyciu polecenia :(nop):

! case ${1#[+-]} in *[!0-9]*) :;; ?*) ! :;; esac && echo Integer
John1024
źródło
5
Co jeśli ciąg zawiera znaki nowej linii? foo\n123\nbarnie jest liczbą całkowitą, ale przejdzie ten test.
godlygeek,
3
To znaczy wersja grep. Wersja skrzynki wygląda poprawnie.
godlygeek,
5

Niezależnie od tego dash, bash, ksh, zshPOSIX shlub posh( "a reimplementacja Bourne shell" sh ); casekonstrukt jest najbardziej powszechnie dostępne i wiarygodne:

case $1 in (*[!0-9]*|"") false ;; (*) true ;; esac
Janis
źródło
Testowałeś to pod dash? To działa dla mnie pod, bashale nie dash.
John1024,
Tak, przetestowałem to również na moim systemie dash; aby przesłuchać wynik dodany echo $?po poleceniu case.
Janis,
Zrobiłem to samo (stabilna Debian), ale nie miałem radości. Aby uzyskać pełny przykład, który działa dla mnie pod moją deską rozdzielczą, zobacz moją Opcję 2 .
John1024,
Hmm, nie mam dostępnej oryginalnej powłoki Bourne'a do przetestowania. Dokumenty, które sprawdziłem na temat „funkcji [w ksh] nie w powłoce Bourne'a” przynajmniej o tym nie wspominają, więc zakładam, że tam były. Nie? - Następnie pomiń nawias wiodący. - OTOH posh(„reimplementacja powłoki Bourne'a”) również nie ma problemu z tym rozwiązaniem.
Janis,
1
@mikeserv; Istnieje kilka powodów, dla których używam zawsze pasujących nawiasów case; jednym z powodów jest opisany przez ciebie błąd, innym jest to, że w edytorach, które mają funkcje oparte na dopasowywaniu nawiasów (vim), zapewnia ono o wiele lepsze wsparcie, i osobiście uważam, że lepiej jest je dopasować. - WRT poshjest POSIX; cóż, cytat ze strony podręcznika, który podałem, sugeruje coś innego, ale chyba nie można polegać na tak nieformalnych stwierdzeniach. Stara skorupa Bourne'a i tak nie jest już tak znacząca teraz, gdy jesteśmy w erze POSIX.
Janis,
1

Możesz użyć -eqtestu na łańcuchu, z samym sobą:

$ 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

Jeśli komunikat o błędzie stanowi problem, przekieruj wyjście błędu do /dev/null:

$ dash -c 'a="0xa"; [ "$a" -eq "$a" ] 2>/dev/null|| echo no'
no
muru
źródło
1
Powiedziałby również, że " 023 "jest to liczba. Zauważ, że działa z myślnikiem, ale nie ze wszystkimi innymi powłokami POSIX, ponieważ zachowanie nie jest określone, jeśli operandy są liczbami całkowitymi dziesiętnymi. Na przykład z ksh powiedziałoby to SHLVLlub 1+1jest liczbą.
Stéphane Chazelas,
0

Spróbuj użyć go jako rozszerzenia arytmetycznego i sprawdź, czy działa. W rzeczywistości musisz być nieco bardziej rygorystyczny, ponieważ rozszerzenia arytmetyczne ignorowałyby na przykład spacje początkowe i końcowe. Więc wykonaj interpretację arytmetyczną i upewnij się, że rozwinięty wynik dokładnie pasuje do oryginalnej zmiennej.

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

Spowodowałoby to również przyjęcie liczb ujemnych - jeśli naprawdę chcesz je wykluczyć, dodaj dodatkowe pole wyboru dla $((${1} >= 0)).

godlygeek
źródło
1
dash nie ma[[
glenn jackman
@glennjackman Whoops. To ma $(( ... ))? Jeśli tak, moja odpowiedź powinna być nadal istotna, muszę tylko dodać dodatkowe cytaty.
godlygeek,
to twoja odpowiedź: dowiedz się.
glenn jackman
Wygląda na to, że tak, więc moja zaktualizowana wersja powinna załatwić sprawę. Nie mam jednak umiejętności testowania, więc daj mi znać, jeśli coś mi umknie.
godlygeek,
Próbowałem: check_if_number 1.2i funkcja zwróciła: dash: 3: arithmetic expression: expecting EOF: "1.2"
John1024
0

Być może z expr?

if expr match "$1" '^\([0-9]\+\)$' > /dev/null; then
  echo "integer"
else 
  echo "non-integer"
fi
steeldriver
źródło
POSIX też matchnie \+jest. Powiedziałby również, że 0 nie jest liczbą. Chceszexpr "x$1" : 'x[0-9]\{1,\}$'
Stéphane Chazelas,
0

W systemie POSIX możesz użyć expr :

$ a=a
$ expr "$a" - 0 >/dev/null 2>&1
$ [ "$?" -lt 2 ] && echo Integer || echo Not Integer
Cuonglm
źródło
Powie, że 0 nie jest liczbą całkowitą (i powiedz -12, że rozwiązanie bash OP zostanie odrzucone). Niektóre exprimplementacje powiedzą, że 999999999999999999999 nie jest liczbą całkowitą. POSIX nie daje żadnej gwarancji, że to zadziała. W praktyce przynajmniej w systemie GNU powiedzą, że „długość” jest liczbą całkowitą.
Stéphane Chazelas
W moim teście działa przynajmniej w Debianie i OSX. Mówi, że liczba całkowita dla 0. Posix zapewnia, że ​​$ a musi być poprawnym wyrażeniem (liczba całkowita) dla wyrażenia arytmetycznego.
cuonglm
Och tak, przepraszam, przeoczyłem twój test za $? <2. Wciąż expr 9999999999999999999 + 0daje mi status wyjścia i 3 expr -12 + 0i expr length + 0dać mi stan 0 wyjścia z GNU expr ( + stringsił string, aby być uznane jako ciąg z GNU expr. expr "$a" - 0Będzie działać lepiej).
Stéphane Chazelas
@ StéphaneChazelas: Och, tak, zaktualizowałem moją odpowiedź. Myślę, że -12jest poprawną liczbą całkowitą i 9999999999999999999spowodował przepełnienie.
cuonglm
0

Oto prosta funkcja stosując tę samą metodę jak Muru jest odpowiedź :

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

Przykład:

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"

Wynik:

'2a3' isn't an integer
'23' is an integer
agc
źródło