/ bin / dash: periksa apakah $ 1 adalah angka

12

Apa cara terbaik untuk memeriksa apakah $ 1 adalah integer di / bin / dash?

Dalam bash, saya bisa melakukan:

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

Tapi itu tampaknya tidak sesuai dengan POSIX dan tanda hubung tidak mendukung itu

Martin Vegter
sumber

Jawaban:

12

Mendeteksi bilangan bulat berikut, positif atau negatif, dan bekerja di bawah dashdan POSIX:

Pilihan 1

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

pilihan 2

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

Atau, dengan sedikit menggunakan perintah :(nop):

! case ${1#[+-]} in *[!0-9]*) :;; ?*) ! :;; esac && echo Integer
John1024
sumber
5
Bagaimana jika string berisi baris baru? foo\n123\nbarbukan bilangan bulat, tetapi akan lulus tes ini.
godlygeek
3
Versi grep, yaitu. Versi case terlihat benar.
godlygeek
5

Entah dash, bash, ksh, zsh, POSIX sh, atau posh( "implementasi ulang dari Bourne shell" sh ); yang casemembangun adalah yang paling banyak tersedia dan dapat diandalkan:

case $1 in (*[!0-9]*|"") false ;; (*) true ;; esac
Janis
sumber
Apakah Anda menguji ini di bawah dash? Ini bekerja untuk saya di bawah bashtetapi tidak dash.
John1024
Ya, saya mengujinya di sistem saya juga dengan dash; untuk menginterogasi hasil yang saya tambahkan echo $?setelah perintah kasus.
Janis
Saya melakukan hal yang sama (Debian stable) tetapi tidak ada sukacita. Untuk contoh lengkap yang berfungsi untuk saya di bawah dasbor saya, lihat Opsi 2 saya .
John1024
Hmm, saya tidak punya shell bourne asli yang tersedia untuk diuji. Dokumen yang saya periksa tentang "fitur [di ksh] tidak di bourne shell" setidaknya tidak menyebutkannya, jadi saya menganggapnya ada di sana. Tidak? - Kemudian abaikan tanda kurung utama. - OTOH, posh("implementasi ulang shell Bourne") juga tidak memiliki masalah dengan solusi itu.
Janis
1
@ mikeserv; Ada beberapa alasan mengapa saya menggunakan tanda kurung yang selalu cocok di case; salah satu alasannya adalah bug yang Anda jelaskan, satu lagi yang dalam editor yang memiliki fitur yang bergantung pada tanda kurung yang cocok (vim) memberikan dukungan yang lebih baik, dan paling tidak saya merasa secara pribadi lebih mudah dibaca untuk mencocokkannya. - WRT poshmenjadi POSIX; Yah, kutipan dari halaman manual yang saya berikan menyarankan sesuatu yang lain, tetapi orang tidak bisa mengandalkan pernyataan informal seperti itu, saya kira. Shell bourne lama tidak lagi signifikan sekarang karena kita berada di era POSIX.
Janis
1

Anda dapat menggunakan -eqtes pada string, dengan sendirinya:

$ 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

Jika pesan kesalahan adalah masalah, redirect output kesalahan ke /dev/null:

$ dash -c 'a="0xa"; [ "$a" -eq "$a" ] 2>/dev/null|| echo no'
no
muru
sumber
1
Bisa juga dikatakan itu " 023 "angka. Perhatikan bahwa ia bekerja dengan tanda hubung, tetapi tidak semua shell POSIX lainnya karena perilakunya tidak ditentukan jika operannya adalah bilangan desimal. Misalnya dengan ksh, itu akan mengatakan itu SHLVLatau 1+1angka.
Stéphane Chazelas
0

Coba gunakan itu sebagai ekspansi aritmatika, dan lihat apakah itu berfungsi. Sebenarnya, Anda harus sedikit lebih ketat dari itu, karena ekspansi aritmatika akan mengabaikan ruang depan dan belakang, misalnya. Jadi lakukan ekspansi aritmatika, dan pastikan bahwa hasil yang diperluas cocok dengan variabel asli dengan tepat.

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

Ini juga akan menerima angka negatif - jika Anda bermaksud mengecualikannya, tambahkan cek tambahan untuk $((${1} >= 0)).

godlygeek
sumber
1
dasbor tidak memiliki[[
glenn jackman
@glennjackman Whoops. Apakah itu $(( ... ))? Jika demikian, jawaban saya masih benar secara materi, saya hanya perlu menambahkan beberapa kutipan tambahan.
godlygeek
ini jawaban Anda: cari tahu.
glenn jackman
Sepertinya begitu, jadi versi saya yang diperbarui harus melakukan trik. Saya tidak memiliki tanda hubung untuk mengujinya, jadi beri tahu saya jika saya melewatkan hal lain.
godlygeek
Saya mencoba: check_if_number 1.2dan fungsinya kembali: dash: 3: arithmetic expression: expecting EOF: "1.2"
John1024
0

Mungkin dengan expr?

if expr match "$1" '^\([0-9]\+\)$' > /dev/null; then
  echo "integer"
else 
  echo "non-integer"
fi
Steeldriver
sumber
tidak matchjuga \+adalah POSIX. Itu juga akan mengatakan 0 bukan angka. Anda inginexpr "x$1" : 'x[0-9]\{1,\}$'
Stéphane Chazelas
0

Dalam sistem POSIX, Anda dapat menggunakan expr :

$ a=a
$ expr "$a" - 0 >/dev/null 2>&1
$ [ "$?" -lt 2 ] && echo Integer || echo Not Integer
cuonglm
sumber
Ini akan mengatakan bahwa 0 bukan bilangan bulat (dan katakan -12 adalah mana solusi bash OP akan ditolak). Beberapa exprimplementasi akan mengatakan bahwa 999999999999999999999 bukan bilangan bulat. POSIX tidak memberikan jaminan bahwa ini akan berhasil. Dalam praktiknya, setidaknya pada sistem GNU, ia akan mengatakan bahwa "panjang" adalah bilangan bulat.
Stéphane Chazelas
Dalam pengujian saya, ini berfungsi setidaknya di Debian dan OSX. Ia mengatakan integer untuk 0. Posix memastikan $ a harus ekspresi yang valid (integer) untuk expr do aritmatika.
cuonglm
Oh ya, maaf, saya telah mengabaikan tes Anda sebesar $? <2. Tetap expr 9999999999999999999 + 0memberi saya status keluar 3 dan expr -12 + 0dan expr length + 0memberi saya status keluar 0 dengan GNU expr ( + stringmemaksa stringuntuk dianggap sebagai string dengan GNU expr. expr "$a" - 0Akan bekerja lebih baik).
Stéphane Chazelas
@ StéphaneChazelas: Oh, ya, perbarui jawaban saya. Saya pikir -12adalah integer yang valid, dan 9999999999999999999memberikan overflow.
cuonglm
0

Inilah fungsi sederhana menggunakan metode yang sama dengan jawaban muru :

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

Contoh:

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"

Keluaran:

'2a3' isn't an integer
'23' is an integer
agc
sumber