Bagaimana saya menguji jika suatu variabel adalah angka di Bash?

599

Saya tidak tahu bagaimana cara memastikan argumen yang diteruskan ke skrip saya adalah angka atau tidak.

Yang ingin saya lakukan adalah sesuatu seperti ini:

test *isnumber* $1 && VAR=$1 || echo "need a number"

Ada bantuan?

Flávio Amieiro
sumber
17
Sebagai tambahan - test && echo "foo" && exit 0 || echo "bar" && exit 1pendekatan yang Anda gunakan mungkin memiliki beberapa efek samping yang tidak diinginkan - jika gema gagal (mungkin output ke FD tertutup), maka exit 0akan dilewati, dan kode kemudian akan mencoba echo "bar". Jika gagal juga, &&kondisinya akan gagal, dan itu bahkan tidak akan dieksekusi exit 1! Menggunakan ifpernyataan aktual daripada &&/ ||kurang rentan terhadap efek samping yang tidak terduga.
Charles Duffy
@CharlesDuffy Itulah jenis pemikiran yang sangat pintar yang hanya bisa dilakukan sebagian besar orang ketika mereka harus melacak bug berbulu ...! Saya tidak pernah berpikir gema dapat mengembalikan kegagalan.
Camilo Martin
6
Agak terlambat ke pesta, tapi aku tahu tentang bahaya yang ditulis Charles, karena aku harus melewati mereka beberapa waktu yang lalu juga. Jadi, inilah 100% pembuktian bodoh (dan mudah dibaca) untuk Anda: [[ $1 =~ "^[0-9]+$" ]] && { echo "number"; exit 0; } || { echo "not a number"; exit 1; }Kurung keriting menunjukkan bahwa segala sesuatu TIDAK boleh dieksekusi dalam sebuah subkulit (yang pastinya akan seperti itu dengan ()menggunakan tanda kurung sebagai gantinya). Peringatan: Jangan pernah melewatkan titik koma terakhir . Kalau tidak, Anda mungkin bashakan mencetak pesan kesalahan paling jelek (dan paling tidak berguna) ...
syntaxerror
5
Ini tidak berfungsi di Ubuntu, kecuali jika Anda tidak menghapus tanda kutip. Jadi seharusnya[[ 12345 =~ ^[0-9]+$ ]] && echo OKKK || echo NOOO
Treviño
4
Anda harus lebih spesifik tentang apa yang Anda maksud dengan "angka" . Bilangan bulat? Nomor titik tetap? Notasi ilmiah ("e")? Apakah ada rentang yang diperlukan (misalnya nilai 64-bit yang tidak ditandatangani), atau apakah Anda mengizinkan angka apa pun yang dapat ditulis?
Toby Speight

Jawaban:

803

Salah satu pendekatan adalah menggunakan ekspresi reguler, seperti:

re='^[0-9]+$'
if ! [[ $yournumber =~ $re ]] ; then
   echo "error: Not a number" >&2; exit 1
fi

Jika nilainya belum tentu bilangan bulat, pertimbangkan untuk mengubah regex dengan tepat; contohnya:

^[0-9]+([.][0-9]+)?$

... atau, untuk menangani angka dengan tanda:

^[+-]?[0-9]+([.][0-9]+)?$
Charles Duffy
sumber
7
+1 untuk pendekatan ini, tetapi berhati-hatilah dengan desimal, lakukan tes ini dengan, misalnya, kesalahan "1,0" atau "1,0" mencetak ": Bukan angka".
sourcerebels
15
Saya menemukan '' exec> & 2; gaung ... 'agak konyol. Just '' echo ...> & 2 ''
lhunath
5
@ Ben, apakah Anda benar-benar ingin menangani lebih dari satu tanda minus? Saya akan membuatnya ^-?daripada ^-*kecuali Anda benar-benar melakukan pekerjaan untuk menangani beberapa inversi dengan benar.
Charles Duffy
4
@SandraSchlichting Membuat semua keluaran di masa mendatang pergi ke stderr. Tidak benar-benar menunjuk ke sini, di mana hanya ada satu gema, tapi itu kebiasaan saya cenderung masuk ke kasus di mana pesan kesalahan span beberapa baris.
Charles Duffy
29
Saya tidak yakin mengapa ekspresi reguler harus disimpan dalam variabel, tetapi jika itu demi kompatibilitas saya tidak berpikir itu perlu. Anda hanya bisa menerapkan ekspresi langsung: [[ $yournumber =~ ^[0-9]+$ ]].
konsolebox
284

Tanpa bashism (bekerja bahkan di System V sh),

case $string in
    ''|*[!0-9]*) echo bad ;;
    *) echo good ;;
esac

Ini menolak string kosong dan string berisi non-digit, menerima yang lainnya.

Angka negatif atau floating-point membutuhkan beberapa pekerjaan tambahan. Gagasannya adalah untuk mengecualikan -/ .dalam pola "buruk" pertama dan menambahkan lebih banyak pola "buruk" yang mengandung penggunaannya yang tidak tepat ( ?*-*/ *.*.*)

jilles
sumber
20
+1 - ini adalah cara portabel yang idiomatis untuk kembali ke cangkang Bourne asli, dan memiliki dukungan bawaan untuk wildcard gaya-global. Jika Anda berasal dari bahasa pemrograman lain, sepertinya menakutkan, tetapi jauh lebih elegan daripada mengatasi kerapuhan berbagai masalah penawaran dan masalah kompatibilitas mundur / menyamping yang tak berujung denganif test ...
tripleee
6
Anda dapat mengubah baris pertama ke ${string#-}(yang tidak bekerja di shell Bourne antik, tetapi bekerja di shell POSIX) untuk menerima bilangan bulat negatif.
Gilles 'SANGAT berhenti menjadi jahat'
4
Juga, ini mudah diperluas ke float - cukup tambahkan '.' | *.*.*ke pola yang tidak diizinkan, dan tambahkan titik ke karakter yang diizinkan. Demikian pula, Anda dapat mengizinkan tanda opsional sebelumnya, meskipun kemudian saya lebih suka case ${string#[-+]}mengabaikan tanda itu.
tripleee
Lihat ini untuk menangani bilangan bulat yang ditandatangani: stackoverflow.com/a/18620446/2013911
Niklas Peter
2
@Dor Kutipan tidak diperlukan, karena perintah case tidak melakukan pemisahan kata dan pembuatan pathname pada kata itu. (Namun, ekspansi dalam pola kasus mungkin perlu mengutip karena menentukan apakah karakter yang cocok dengan pola itu literal atau khusus.)
jilles
193

Solusi berikut juga dapat digunakan dalam cangkang dasar seperti Bourne tanpa perlu ekspresi reguler. Pada dasarnya setiap operasi evaluasi nilai numerik menggunakan non-angka akan menghasilkan kesalahan yang secara implisit akan dianggap salah dalam shell:

"$var" -eq "$var"

seperti dalam:

#!/bin/bash

var=a

if [ -n "$var" ] && [ "$var" -eq "$var" ] 2>/dev/null; then
  echo number
else
  echo not a number
fi

Anda juga dapat menguji untuk $? kode pengembalian operasi yang lebih eksplisit:

[ -n "$var" ] && [ "$var" -eq "$var" ] 2>/dev/null
if [ $? -ne 0 ]; then
   echo $var is not number
fi

Ada pengalihan kesalahan standar untuk menyembunyikan pesan "ekspresi integer yang diharapkan" yang dicetak bash seandainya kita tidak memiliki nomor.

CAVEATS (terima kasih untuk komentar di bawah):

  • Angka dengan titik desimal tidak diidentifikasi sebagai "angka" yang valid
  • Menggunakan [[ ]]alih-alih [ ]akan selalu dievaluasitrue
  • Sebagian besar cangkang non-Bash akan selalu mengevaluasi ekspresi ini sebagai true
  • Perilaku di Bash tidak berdokumen dan karenanya dapat berubah tanpa peringatan
  • Jika nilai termasuk spasi setelah angka (misalnya "1 a") menghasilkan kesalahan, seperti bash: [[: 1 a: syntax error in expression (error token is "a")
  • Jika nilainya sama dengan var-name (mis. I = "i"), menghasilkan kesalahan, seperti bash: [[: i: expression recursion level exceeded (error token is "i")
Alberto Zaccagni
sumber
8
Saya masih merekomendasikan ini (tetapi dengan variabel yang dikutip untuk memungkinkan string kosong), karena hasilnya dijamin dapat digunakan sebagai angka di Bash, tidak peduli apa.
l0b0
21
Berhati-hatilah untuk menggunakan kurung tunggal; [[ a -eq a ]]bernilai true (kedua argumen dikonversikan ke nol)
Tgr
3
Sangat bagus! Perhatikan ini hanya berfungsi untuk bilangan bulat, bukan angka apa pun. Saya perlu memeriksa satu argumen yang harus berupa bilangan bulat, jadi ini bekerja dengan baik:if ! [ $# -eq 1 -o "$1" -eq "$1" ] 2>/dev/null; then
haridsv
6
Saya akan sangat menyarankan terhadap metode ini karena jumlah cangkang yang tidak signifikan yang [dibangun akan mengevaluasi argumen sebagai aritmatika. Itu benar dalam ksh93 dan mksh. Selanjutnya, karena kedua array dukungan tersebut, ada peluang mudah untuk injeksi kode. Gunakan pencocokan pola sebagai gantinya.
ormaaj
3
@AlbertoZaccagni, dalam rilis bash saat ini, nilai-nilai ini ditafsirkan dengan aturan konteks numerik hanya untuk [[ ]]tetapi tidak untuk [ ]. Yang mengatakan, perilaku ini tidak ditentukan oleh standar POSIX untuk testdan dalam dokumentasi bash sendiri; versi masa depan dari bash dapat memodifikasi perilaku agar sesuai dengan ksh tanpa melanggar janji perilaku yang didokumentasikan, jadi mengandalkan perilaku yang ada saat ini tidak dijamin aman.
Charles Duffy
43

Ini menguji apakah suatu bilangan merupakan bilangan bulat non-negatif dan keduanya tidak tergantung pada shell (yaitu tanpa bashisme) dan hanya menggunakan built-in shell:

SALAH.

Karena jawaban pertama ini (di bawah) memungkinkan untuk bilangan bulat dengan karakter di dalamnya selama yang pertama tidak pertama dalam variabel.

[ -z "${num##[0-9]*}" ] && echo "is a number" || echo "is not a number";

BENAR .

Sebagaimana jilles berkomentar dan menyarankan dalam jawabannya, ini adalah cara yang benar untuk melakukannya dengan menggunakan pola shell.

[ ! -z "${num##*[!0-9]*}" ] && echo "is a number" || echo "is not a number";
mrucci
sumber
5
Ini tidak berfungsi dengan baik, ia menerima string apa pun yang dimulai dengan angka. Perhatikan bahwa KATA dalam $ {VAR ## WORD} dan sejenisnya adalah pola shell, bukan ekspresi reguler.
jilles
2
Bisakah Anda menerjemahkan ungkapan itu ke dalam bahasa Inggris? Saya benar-benar ingin menggunakannya, tetapi saya tidak cukup memahaminya untuk mempercayainya, bahkan setelah membaca halaman manual bash.
CivFan
2
*[!0-9]*adalah pola yang cocok dengan semua string dengan setidaknya 1 karakter non-digit. ${num##*[!0-9]*}adalah "perluasan parameter" tempat kami mengambil konten numvariabel dan menghapus string terpanjang yang cocok dengan pola. Jika hasil ekspansi parameter tidak kosong ( ! [ -z ${...} ]) maka itu adalah angka karena tidak mengandung karakter non-digit.
mrucci
Sayangnya ini gagal jika ada angka dalam argumen, meskipun itu bukan angka yang valid. Misalnya "exam1ple" atau "a2b".
studgeek
Keduanya gagal dengan122s :-(
Hastur
40

Tidak ada yang menyarankan pencocokan pola diperpanjang bash :

[[ $1 == ?(-)+([0-9]) ]] && echo "$1 is an integer"
glenn jackman
sumber
5
Glenn, saya menghapus shopt -s extglobdari posting Anda (yang saya undur, itu salah satu jawaban favorit saya di sini), karena dalam Conditional Constructs Anda dapat membaca: Ketika operator ==dan !=digunakan, string di sebelah kanan operator dianggap sebagai pola dan cocok sesuai dengan aturan yang dijelaskan di bawah ini dalam Pola Pencocokan , seolah-olah extglobopsi shell diaktifkan. Saya harap kamu tidak keberatan!
gniourf_gniourf
Dalam konteks seperti itu, Anda tidak perlu shopt extglob... itu hal yang baik untuk diketahui!
gniourf_gniourf
Bekerja dengan baik untuk bilangan bulat sederhana.
2
@Jdamian: Anda benar, ini ditambahkan di Bash 4.1 (yang dirilis pada akhir 2009 ... Bash 3.2 dirilis pada 2006 ... sekarang perangkat lunak antik, maaf untuk mereka yang terjebak di masa lalu). Juga, Anda bisa berpendapat bahwa extglobs mana yang diperkenalkan dalam versi 2.02 (dirilis pada tahun 1998), dan tidak berfungsi dalam versi <2.02 ... Sekarang komentar Anda di sini akan berfungsi sebagai peringatan tentang versi yang lebih lama.
gniourf_gniourf
1
Variabel di dalam [[...]]tidak tunduk pada pemisahan kata atau ekspansi glob.
glenn jackman
26

Saya terkejut dengan solusi yang langsung mem-parsing format angka di shell. shell tidak cocok untuk ini, karena DSL untuk mengendalikan file dan proses. Ada banyak pengurai yang sedikit lebih rendah ke bawah, misalnya:

isdecimal() {
  # filter octal/hex/ord()
  num=$(printf '%s' "$1" | sed "s/^0*\([1-9]\)/\1/; s/'/^/")

  test "$num" && printf '%f' "$num" >/dev/null 2>&1
}

Ubah '% f' ke format apa pun yang Anda butuhkan.

pixelbeat
sumber
4
isnumber(){ printf '%f' "$1" &>/dev/null && echo "this is a number" || echo "not a number"; }
Gilles Quenot
4
@sputnick versi Anda memecah semantik nilai kembali yang melekat (dan berguna) dari fungsi asli. Jadi, alih-alih, tinggalkan saja fungsi apa adanya, dan gunakan:isnumber 23 && echo "this is a number" || echo "not a number"
michael
4
Bukankah ini seharusnya juga 2>/dev/null, sehingga isnumber "foo"tidak mencemari stderr?
gioele
4
Untuk memanggil shell modern seperti bash "DSL untuk mengendalikan file dan proses" mengabaikan bahwa mereka digunakan untuk lebih dari itu - beberapa distro telah membangun seluruh manajer paket dan antarmuka web di atasnya (seburuk mungkin). File batch sesuai dengan deskripsi Anda, karena pengaturan variabel sekalipun ada yang sulit.
Camilo Martin
7
Lucu bahwa Anda mencoba menjadi pintar dengan menyalin beberapa idiom dari bahasa lain. Sayangnya ini tidak bekerja di shell. Kerang sangat istimewa, dan tanpa pengetahuan yang kuat tentang mereka, Anda cenderung menulis kode yang rusak. Kode Anda rusak: isnumber "'a"akan kembali benar. Ini didokumentasikan dalam spesifikasi POSIX di mana Anda akan membaca: Jika karakter utama adalah kutipan-tunggal atau kutipan ganda, nilainya akan menjadi nilai numerik dalam kumpulan kode karakter yang mendasari mengikuti kutipan-tunggal atau kutipan ganda .
gniourf_gniourf
16

Saya melihat jawabannya dan ... menyadari bahwa tidak ada yang memikirkan angka FLOAT (dengan titik)!

Menggunakan grep juga bagus.
-E berarti extended regexp
-q berarti tenang (tidak menggema)
-qE adalah kombinasi keduanya.

Untuk menguji langsung di baris perintah:

$ echo "32" | grep -E ^\-?[0-9]?\.?[0-9]+$  
# answer is: 32

$ echo "3a2" | grep -E ^\-?[0-9]?\.?[0-9]+$  
# answer is empty (false)

$ echo ".5" | grep -E ^\-?[0-9]?\.?[0-9]+$  
# answer .5

$ echo "3.2" | grep -E ^\-?[0-9]?\.?[0-9]+$  
# answer is 3.2

Menggunakan dalam skrip bash:

check=`echo "$1" | grep -E ^\-?[0-9]*\.?[0-9]+$`

if [ "$check" != '' ]; then    
  # it IS numeric
  echo "Yeap!"
else
  # it is NOT numeric.
  echo "nooop"
fi

Untuk mencocokkan JUST integer, gunakan ini:

# change check line to:
check=`echo "$1" | grep -E ^\-?[0-9]+$`
Sergio Abreu
sumber
Solusi menggunakan awk oleh triple_r dan tripleee berfungsi dengan float.
Ken Jackson
Terima kasih untuk ini dan poin yang sangat bagus! Karena pertanyaannya sebenarnya bagaimana memeriksa apakah itu angka dan bukan hanya bilangan bulat.
Tanasis
Saya juga berterima kasih kepada Tanasis! Mari kita selalu saling membantu.
Sergio Abreu
12

Cukup tindak lanjuti ke @mary. Tetapi karena saya tidak memiliki cukup perwakilan, tidak dapat memposting ini sebagai komentar untuk posting itu. Bagaimanapun, inilah yang saya gunakan:

isnum() { awk -v a="$1" 'BEGIN {print (a == a + 0)}'; }

Fungsi akan mengembalikan "1" jika argumennya adalah angka, jika tidak akan mengembalikan "0". Ini berfungsi untuk bilangan bulat dan juga mengapung. Penggunaannya adalah seperti:

n=-2.05e+07
res=`isnum "$n"`
if [ "$res" == "1" ]; then
     echo "$n is a number"
else
     echo "$n is not a number"
fi
triple_r
sumber
4
Mencetak nomor kurang berguna daripada mengatur kode keluar. 'BEGIN { exit(1-(a==a+0)) }'sedikit sulit untuk grok tetapi dapat digunakan dalam fungsi yang mengembalikan benar atau salah seperti [, grep -q, dll
tripleee
9
test -z "${i//[0-9]}" && echo digits || echo no no no

${i//[0-9]}mengganti digit apa pun dalam nilai $idengan string kosong, lihat man -P 'less +/parameter\/' bash. -zmemeriksa apakah string yang dihasilkan memiliki panjang nol.

jika Anda juga ingin mengecualikan kasing saat $ikosong, Anda dapat menggunakan salah satu konstruksi ini:

test -n "$i" && test -z "${i//[0-9]}" && echo digits || echo not a number
[[ -n "$i" && -z "${i//[0-9]}" ]] && echo digits || echo not a number
pengguna2683246
sumber
Acungan jempol terutama untuk man -P 'less +/parameter\/' bashbagian itu. Belajar sesuatu yang baru setiap hari. :)
David
@sjas Anda dapat dengan mudah menambahkan \-ekspresi reguler untuk mengatasi masalah ini. Gunakan [0-9\-\.\+]untuk menghitung pelampung dan nomor yang ditandatangani.
user2683246
@jas ok, salahku
user2683246
@sjasecho $i | python -c $'import sys\ntry:\n float(sys.stdin.read().rstrip())\nexcept:\n sys.exit(1)' && echo yes || echo no
user2683246
9

Untuk masalah saya, saya hanya perlu memastikan bahwa pengguna tidak sengaja memasukkan beberapa teks sehingga saya mencoba untuk membuatnya tetap sederhana dan mudah dibaca

isNumber() {
    (( $1 )) 2>/dev/null
}

Menurut halaman manual ini cukup banyak melakukan apa yang saya inginkan

Jika nilai ekspresi bukan nol, status pengembalian adalah 0

Untuk mencegah pesan kesalahan yang tidak diinginkan untuk string yang "mungkin angka", saya mengabaikan output kesalahan

$ (( 2s ))
bash: ((: 2s: value too great for base (error token is "2s")
Hachi
sumber
Ini lebih seperti isInteger. Tapi terima kasih luar biasa!
Naheel
8

Pertanyaan lama, tapi saya hanya ingin memperbaiki solusi saya. Yang ini tidak memerlukan trik shell aneh, atau mengandalkan sesuatu yang belum ada selamanya.

if [ -n "$(printf '%s\n' "$var" | sed 's/[0-9]//g')" ]; then
    echo 'is not numeric'
else
    echo 'is numeric'
fi

Pada dasarnya itu hanya menghapus semua digit dari input, dan jika Anda pergi dengan string yang tidak nol, maka itu bukan angka.

Sammitch
sumber
Ini gagal karena kosong var.
gniourf_gniourf
Atau untuk variabel dengan mengikuti baris baru atau semacamnya $'0\n\n\n1\n\n\n2\n\n\n3\n'.
gniourf_gniourf
7

Tidak dapat berkomentar, jadi saya akan menambahkan jawaban saya sendiri, yang merupakan ekstensi untuk jawaban glenn jackman menggunakan pencocokan pola bash.

Kebutuhan awal saya adalah mengidentifikasi angka dan membedakan bilangan bulat dan pelampung. Definisi fungsi yang dikurangkan menjadi:

function isInteger() {
    [[ ${1} == ?(-)+([0-9]) ]]
}

function isFloat() {
    [[ ${1} == ?(-)@(+([0-9]).*([0-9])|*([0-9]).+([0-9]))?(E?(-|+)+([0-9])) ]]
}

Saya menggunakan pengujian unit (dengan shUnit2) untuk memvalidasi pola saya berfungsi sebagaimana dimaksud:

oneTimeSetUp() {
    int_values="0 123 -0 -123"
    float_values="0.0 0. .0 -0.0 -0. -.0 \
        123.456 123. .456 -123.456 -123. -.456
        123.456E08 123.E08 .456E08 -123.456E08 -123.E08 -.456E08 \
        123.456E+08 123.E+08 .456E+08 -123.456E+08 -123.E+08 -.456E+08 \
        123.456E-08 123.E-08 .456E-08 -123.456E-08 -123.E-08 -.456E-08"
}

testIsIntegerIsFloat() {
    local value
    for value in ${int_values}
    do
        assertTrue "${value} should be tested as integer" "isInteger ${value}"
        assertFalse "${value} should not be tested as float" "isFloat ${value}"
    done

    for value in ${float_values}
    do
        assertTrue "${value} should be tested as float" "isFloat ${value}"
        assertFalse "${value} should not be tested as integer" "isInteger ${value}"
    done

}

Catatan: Pola isFloat dapat dimodifikasi agar lebih toleran tentang titik desimal ( @(.,)) dan simbol E ( @(Ee)). Unit saya menguji hanya nilai yang bilangan bulat atau mengambang, tetapi tidak ada input yang tidak valid.

karttu
sumber
Maaf, tidak mengerti bagaimana fungsi edit dimaksudkan untuk digunakan.
3ronco
6

Saya akan mencoba ini:

printf "%g" "$var" &> /dev/null
if [[ $? == 0 ]] ; then
    echo "$var is a number."
else
    echo "$var is not a number."
fi

Catatan: ini mengenali nan dan inf sebagai angka.

meluap
sumber
2
baik duplikat, atau mungkin lebih cocok sebagai komentar, jawaban pixelbeat (menggunakan %fmungkin juga lebih baik)
michael
3
Alih-alih memeriksa kode status sebelumnya, mengapa tidak memasukkannya ifsendiri? Itu yang ifterjadi ...if printf "%g" "$var" &> /dev/null; then ...
Camilo Martin
3
Ini memiliki peringatan lain. Ini akan memvalidasi string kosong, dan string seperti 'a.
gniourf_gniourf
6

Jawaban yang jelas telah diberikan oleh @charles Dufy dan lainnya. Solusi bash murni akan menggunakan yang berikut:

string="-12,345"
if [[ "$string" =~ ^-?[0-9]+[.,]?[0-9]*$ ]]
then
    echo $string is a number
else
    echo $string is not a number
fi

Meskipun untuk bilangan real tidak wajib memiliki nomor sebelum titik radix .

Untuk memberikan dukungan yang lebih menyeluruh tentang angka mengambang dan notasi ilmiah (banyak program di C / Fortran atau yang akan mengekspor float dengan cara ini), tambahan yang bermanfaat untuk baris ini adalah sebagai berikut:

string="1.2345E-67"
if [[ "$string" =~ ^-?[0-9]*[.,]?[0-9]*[eE]?-?[0-9]+$ ]]
then
    echo $string is a number
else
    echo $string is not a number
fi

Jadi mengarah ke cara untuk membedakan jenis angka, jika Anda mencari jenis tertentu:

string="-12,345"
if [[ "$string" =~ ^-?[0-9]+$ ]]
then
    echo $string is an integer
elif [[ "$string" =~ ^-?[0-9]*[.,]?[0-9]*$ ]]
then
    echo $string is a float
elif [[ "$string" =~ ^-?[0-9]*[.,]?[0-9]*[eE]-?[0-9]+$ ]]
then
    echo $string is a scientific number
else
    echo $string is not a number
fi

Catatan: Kita dapat membuat daftar persyaratan sintaksis untuk notasi desimal dan ilmiah, satu untuk memungkinkan koma sebagai titik radix, serta "." Kami kemudian akan menegaskan bahwa harus ada hanya satu titik radix tersebut. Mungkin ada dua tanda +/- dalam float [Ee]. Saya telah belajar beberapa aturan lagi dari karya Aulu, dan menguji terhadap string buruk seperti '' '-' '-E-1' '0-0'. Berikut adalah alat regex / substring / expr saya yang tampaknya bertahan:

parse_num() {
 local r=`expr "$1" : '.*\([.,]\)' 2>/dev/null | tr -d '\n'` 
 nat='^[+-]?[0-9]+[.,]?$' \
 dot="${1%[.,]*}${r}${1##*[.,]}" \
 float='^[\+\-]?([.,0-9]+[Ee]?[-+]?|)[0-9]+$'
 [[ "$1" == $dot ]] && [[ "$1" =~ $float ]] || [[ "$1" =~ $nat ]]
} # usage: parse_num -123.456
Aulo
sumber
6
[[ $1 =~ ^-?[0-9]+$ ]] && echo "number"

Jangan lupa -untuk memasukkan angka negatif!

D_I
sumber
Apa versi minimum dari bash? Saya baru saja mendapat bash: operator binary kondisional yang diharapkan bash: kesalahan sintaks dekat token yang tidak terduga `= ~ '
Paul Hargreaves
1
@PaulHargreaves =~ada setidaknya sejauh bash 3.0.
Gilles 'SANGAT berhenti menjadi jahat'
@PaulHargreaves Anda mungkin memiliki masalah dengan operan pertama Anda, mis. Terlalu banyak tanda kutip atau serupa
Joshua Clayton
@JoshuaClayton Saya bertanya tentang versi karena bash sangat tua pada kotak Solaris 7, yang masih kita miliki dan tidak mendukung = ~
Paul Hargreaves
6

Ini dapat dicapai dengan menggunakan grepuntuk melihat apakah variabel tersebut cocok dengan ekspresi reguler yang diperluas.

Bilangan bulat uji 1120:

yournumber=1120
if echo "$yournumber" | grep -qE '^[0-9]+$'; then
    echo "Valid number."
else
    echo "Error: not a number."
fi

Keluaran: Valid number.

Tes bukan bilangan bulat 1120a:

yournumber=1120a
if echo "$yournumber" | grep -qE '^[0-9]+$'; then
    echo "Valid number."
else
    echo "Error: not a number."
fi

Keluaran: Error: not a number.


Penjelasan

  • The grep, -Eswitch memungkinkan kita untuk menggunakan ekspresi reguler yang diperluas '^[0-9]+$'. Ekspresi reguler ini berarti variabel hanya boleh []berisi angka 0-9nol hingga sembilan dari ^awal hingga $akhir variabel dan harus memiliki setidaknya +satu karakter.
  • The grep, yang -qberalih tenang mematikan output apapun apakah atau tidak menemukan apa-apa.
  • ifmemeriksa status keluar dari grep. Status keluar 0berarti sukses dan yang lebih besar berarti kesalahan. The grepperintah memiliki status keluar dari 0jika menemukan kecocokan dan 1ketika tidak;

Jadi menyatukan semuanya, dalam ifpengujian, kita echovariabel $yournumberdan |pipa itu grepyang dengan -qswitch diam-diam cocok dengan -Eekspresi '^[0-9]+$'ekspresi reguler diperpanjang . Status keluar grepakan 0jika grepberhasil menemukan kecocokan dan 1jika tidak. Jika berhasil mencocokkan, kami echo "Valid number.". Jika gagal mencocokkan, kami echo "Error: not a number.".


Untuk Mengapung atau Ganda

Kami hanya dapat mengubah ekspresi reguler dari '^[0-9]+$'menjadi '^[0-9]*\.?[0-9]+$'untuk mengapung atau ganda.

Test float 1120.01:

yournumber=1120.01
if echo "$yournumber" | grep -qE '^[0-9]*\.?[0-9]+$'; then
    echo "Valid number."
else
    echo "Error: not a number."
fi

Keluaran: Valid number.

Test float 11.20.01:

yournumber=11.20.01
if echo "$yournumber" | grep -qE '^[0-9]*\.?[0-9]+$'; then
    echo "Valid number."
else
    echo "Error: not a number."
fi

Keluaran: Error: not a number.


Untuk Negatif

Untuk mengizinkan bilangan bulat negatif, cukup ubah ekspresi reguler dari '^[0-9]+$'menjadi '^\-?[0-9]+$'.

Untuk memungkinkan mengapung atau menggandakan negatif, cukup ubah ekspresi reguler dari '^[0-9]*\.?[0-9]+$'menjadi '^\-?[0-9]*\.?[0-9]+$'.

Joseph Shih
sumber
Anda benar, @CharlesDuffy. Terima kasih. Saya membersihkan jawabannya.
Joseph Shih
Benar sekali lagi, @CharlesDuffy. Tetap!
Joseph Shih
1
LGTM; jawaban yang telah diedit memiliki +1 saya. Satu-satunya hal yang akan saya lakukan secara berbeda pada saat ini hanyalah masalah pendapat daripada kebenaran (f / e, menggunakan [-]bukan \-dan [.]bukannya \.sedikit lebih bertele-tele, tetapi itu berarti string Anda tidak harus berubah jika mereka ' digunakan dalam konteks di mana backslash dikonsumsi).
Charles Duffy
4

http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_04_03.html

Anda juga dapat menggunakan kelas karakter bash.

if [[ $VAR = *[[:digit:]]* ]]; then
 echo "$VAR is numeric"
else
 echo "$VAR is not numeric"
fi

Numerik akan menyertakan spasi, titik desimal, dan "e" atau "E" untuk titik mengambang.

Tetapi, jika Anda menentukan nomor heks C-style, yaitu "0xffff" atau "0XFFFF", [[: digit:]] mengembalikan true. Sedikit jebakan di sini, bash memungkinkan Anda melakukan sesuatu seperti "0xAZ00" dan masih menghitungnya sebagai digit (bukankah ini dari beberapa kekhasan aneh dari kompiler GCC yang memungkinkan Anda menggunakan notasi 0x untuk pangkalan selain dari 16 ??? )

Anda mungkin ingin menguji "0x" atau "0X" sebelum menguji apakah itu numerik jika input Anda benar-benar tidak dapat dipercaya, kecuali jika Anda ingin menerima nomor hex. Itu akan dicapai dengan:

if [[ ${VARIABLE:1:2} = "0x" ]] || [[ ${VARIABLE:1:2} = "0X" ]]; then echo "$VAR is not numeric"; fi
ultrasawblade
sumber
17
[[ $VAR = *[[:digit:]]* ]]akan mengembalikan true jika variabel berisi angka, bukan jika itu adalah bilangan bulat.
glenn jackman
[[ "z3*&" = *[[:digit:]]* ]] && echo "numeric"cetakan numeric. Diuji dalam versi bash 3.2.25(1)-release.
Jdamian
1
@ultraswadable, solusi Anda mendeteksi string yang berisi, setidaknya, satu digit dikelilingi (atau tidak) oleh karakter lain. Saya menurunkan suara.
Jdamian
Karenanya, pendekatan yang jelas benar adalah untuk membalikkan ini, dan gunakan[[ -n $VAR && $VAR != *[^[:digit:]]* ]]
eschwartz
@ Eschwartz, solusi Anda tidak bekerja dengan angka negatif
Angel
4

Cara paling sederhana adalah memeriksa apakah itu berisi karakter non-digit. Anda mengganti semua karakter digit dengan apa-apa dan memeriksa panjangnya. Jika ada panjang, itu bukan angka.

if [[ ! -n ${input//[0-9]/} ]]; then
    echo "Input Is A Number"
fi
Andy
sumber
2
Untuk menangani angka negatif akan membutuhkan pendekatan yang lebih rumit.
Andy
... Atau tanda positif opsional.
tripleee
@ tripleee saya ingin melihat pendekatan Anda jika Anda tahu cara melakukannya.
Andy
4

Karena saya harus mengutak-atik ini dan akhir-akhir ini menyukai pendekatan karttu dengan unit test yang paling. Saya merevisi kode dan menambahkan beberapa solusi lain juga, coba sendiri untuk melihat hasilnya:

#!/bin/bash

    # N={0,1,2,3,...} by syntaxerror
function isNaturalNumber()
{
 [[ ${1} =~ ^[0-9]+$ ]]
}
    # Z={...,-2,-1,0,1,2,...} by karttu
function isInteger() 
{
 [[ ${1} == ?(-)+([0-9]) ]]
}
    # Q={...,-½,-¼,0.0,¼,½,...} by karttu
function isFloat() 
{
 [[ ${1} == ?(-)@(+([0-9]).*([0-9])|*([0-9]).+([0-9]))?(E?(-|+)+([0-9])) ]]
}
    # R={...,-1,-½,-¼,0.E+n,¼,½,1,...}
function isNumber()
{
 isNaturalNumber $1 || isInteger $1 || isFloat $1
}

bools=("TRUE" "FALSE")
int_values="0 123 -0 -123"
float_values="0.0 0. .0 -0.0 -0. -.0 \
    123.456 123. .456 -123.456 -123. -.456 \
    123.456E08 123.E08 .456E08 -123.456E08 -123.E08 -.456E08 \
    123.456E+08 123.E+08 .456E+08 -123.456E+08 -123.E+08 -.456E+08 \
    123.456E-08 123.E-08 .456E-08 -123.456E-08 -123.E-08 -.456E-08"
false_values="blah meh mooh blah5 67mooh a123bc"

for value in ${int_values} ${float_values} ${false_values}
do
    printf "  %5s=%-30s" $(isNaturalNumber $value) ${bools[$?]} $(printf "isNaturalNumber(%s)" $value)
    printf "%5s=%-24s" $(isInteger $value) ${bools[$?]} $(printf "isInteger(%s)" $value)
    printf "%5s=%-24s" $(isFloat $value) ${bools[$?]} $(printf "isFloat(%s)" $value)
    printf "%5s=%-24s\n" $(isNumber $value) ${bools[$?]} $(printf "isNumber(%s)" $value)
done

Jadi isNumber () termasuk tanda hubung, koma dan notasi eksponensial dan karenanya mengembalikan BENAR pada bilangan bulat & mengapung di mana di sisi lain isFloat () mengembalikan FALSE pada nilai integer dan isInteger () juga mengembalikan FALSE pada float. Untuk kenyamanan Anda semua sebagai satu liners:

isNaturalNumber() { [[ ${1} =~ ^[0-9]+$ ]]; }
isInteger() { [[ ${1} == ?(-)+([0-9]) ]]; }
isFloat() { [[ ${1} == ?(-)@(+([0-9]).*([0-9])|*([0-9]).+([0-9]))?(E?(-|+)+([0-9])) ]]; }
isNumber() { isNaturalNumber $1 || isInteger $1 || isFloat $1; }
3ronco
sumber
Secara pribadi saya akan menghapus functionkata kunci karena tidak melakukan apa pun yang bermanfaat. Juga, saya tidak yakin tentang kegunaan nilai pengembalian. Kecuali ditentukan lain, fungsi akan mengembalikan status keluar dari perintah terakhir, jadi Anda tidak perlu melakukan returnapa pun sendiri.
Tom Fenech
Bagus, memang returnmembingungkan dan membuatnya kurang mudah dibaca. Menggunakan functionkata kunci atau tidak lebih merupakan masalah selera pribadi setidaknya saya menghapusnya dari satu baris untuk menghemat ruang. Terima kasih.
3ronco
Jangan lupa bahwa tanda titik koma diperlukan setelah pengujian untuk versi satu-baris.
Tom Fenech
2
isNumber akan mengembalikan 'true' pada string apa pun yang memiliki nomor di dalamnya.
DrStrangepork
@DrStrangepork Memang, array false_values ​​saya hilang kasus itu. Saya akan memeriksanya. Terima kasih atas petunjuknya.
3ronco
4

Saya menggunakan expr . Ini mengembalikan bukan nol jika Anda mencoba menambahkan nol ke nilai non-numerik:

if expr -- "$number" + 0 > /dev/null 2>&1
then
    echo "$number is a number"
else
    echo "$number isn't a number"
fi

Mungkin dimungkinkan untuk menggunakan bc jika Anda membutuhkan non-integer, tetapi saya tidak percaya bcmemiliki perilaku yang sama. Menambahkan nol ke non-angka membuat Anda nol dan mengembalikan nilai nol juga. Mungkin Anda bisa menggabungkan bcdan expr. Gunakan bcuntuk menambahkan nol $number. Jika jawabannya adalah 0, maka cobalah expruntuk memverifikasi bahwa $numberitu bukan nol.

David W.
sumber
1
Ini agak buruk. Untuk membuatnya sedikit lebih baik, Anda harus menggunakan expr -- "$number" + 0; namun ini masih akan berpura-pura 0 isn't a number. Dari man expr:Exit status is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION is null or 0,
gniourf_gniourf
3

Saya suka jawaban Alberto Zaccagni.

if [ "$var" -eq "$var" ] 2>/dev/null; then

Prasyarat penting: - tidak ada subkulit yang muncul - tidak ada parser RE yang dipanggil - sebagian besar aplikasi shell tidak menggunakan bilangan real

Tetapi jika $varkompleks (misalnya akses array asosiatif), dan jika angka tersebut akan menjadi bilangan bulat non-negatif (kebanyakan kasus penggunaan), maka ini mungkin lebih efisien?

if [ "$var" -ge 0 ] 2> /dev/null; then ..
pengguna3895088
sumber
2

Saya menggunakan printf sebagai jawaban lain yang disebutkan, jika Anda memberikan string format "% f" atau "% i" printf akan melakukan pengecekan untuk Anda. Lebih mudah daripada menciptakan kembali cek, sintaksinya sederhana dan pendek dan printf ada di mana-mana. Jadi itu pilihan yang layak menurut saya - Anda juga dapat menggunakan ide berikut untuk memeriksa berbagai hal, itu tidak hanya berguna untuk memeriksa angka.

declare  -r CHECK_FLOAT="%f"  
declare  -r CHECK_INTEGER="%i"  

 ## <arg 1> Number - Number to check  
 ## <arg 2> String - Number type to check  
 ## <arg 3> String - Error message  
function check_number() { 
  local NUMBER="${1}" 
  local NUMBER_TYPE="${2}" 
  local ERROR_MESG="${3}"
  local -i PASS=1 
  local -i FAIL=0   
  case "${NUMBER_TYPE}" in 
    "${CHECK_FLOAT}") 
        if ((! $(printf "${CHECK_FLOAT}" "${NUMBER}" &>/dev/random;echo $?))); then 
           echo "${PASS}"
        else 
           echo "${ERROR_MESG}" 1>&2
           echo "${FAIL}"
        fi 
        ;;                 
    "${CHECK_INTEGER}") 
        if ((! $(printf "${CHECK_INTEGER}" "${NUMBER}" &>/dev/random;echo $?))); then 
           echo "${PASS}"
        else 
           echo "${ERROR_MESG}" 1>&2
           echo "${FAIL}"
        fi 
        ;;                 
                     *) 
        echo "Invalid number type format: ${NUMBER_TYPE} to check_number()." 1>&2
        echo "${FAIL}"
        ;;                 
   esac
} 

>$ var=45

>$ (($(check_number $var "${CHECK_INTEGER}" "Error: Found $var - An integer is required."))) && { echo "$var+5" | bc; }


sumber
2

ekspresi reguler vs ekspansi parameter

Sebagai jawaban Charles Duffy berhasil, tetapi hanya digunakanekspresi reguler , dan saya tahu ini lambat, saya ingin menunjukkan cara lain, hanya menggunakanekspansi parameter :

Hanya untuk bilangan bulat positif:

is_num() { [ "$1" ] && [ -z "${1//[0-9]}" ] ;}

Untuk bilangan bulat:

is_num() { 
    local chk=${1#[+-]};
    [ "$chk" ] && [ -z "${chk//[0-9]}" ]
}

Kemudian untuk mengambang:

is_num() { 
    local chk=${1#[+-]};
    chk=${chk/.}
    [ "$chk" ] && [ -z "${chk//[0-9]}" ]
}

Untuk mencocokkan permintaan awal:

set -- "foo bar"
is_num "$1" && VAR=$1 || echo "need a number"
need a number

set -- "+3.141592"
is_num "$1" && VAR=$1 || echo "need a number"

echo $VAR
+3.141592

Sekarang sedikit perbandingan:

Ada cek yang sama berdasarkan jawaban Charles Duffy :

cdIs_num() { 
    local re='^[+-]?[0-9]+([.][0-9]+)?$';
    [[ $1 =~ $re ]]
}

Beberapa tes:

if is_num foo;then echo It\'s a number ;else echo Not a number;fi
Not a number
if cdIs_num foo;then echo It\'s a number ;else echo Not a number;fi
Not a number
if is_num 25;then echo It\'s a number ;else echo Not a number;fi
It's a number
if cdIs_num 25;then echo It\'s a number ;else echo Not a number;fi
It's a number
if is_num 3+4;then echo It\'s a number ;else echo Not a number;fi
Not a number
if cdIs_num 3+4;then echo It\'s a number ;else echo Not a number;fi
Not a number
if is_num 3.1415;then echo It\'s a number ;else echo Not a number;fi
It's a number
if cdIs_num 3.1415;then echo It\'s a number ;else echo Not a number;fi
It's a number

Baiklah tidak apa apa. Sekarang berapa banyak waktu yang diperlukan untuk semua ini (Pada raspberry pi saya):

time for i in {1..1000};do is_num +3.14159265;done
real    0m2.476s
user    0m1.235s
sys     0m0.000s

Kemudian dengan ekspresi reguler:

time for i in {1..1000};do cdIs_num +3.14159265;done
real    0m4.363s
user    0m2.168s
sys     0m0.000s
F. Hauri
sumber
Saya setuju, bagaimanapun, saya lebih suka untuk tidak menggunakan regex, ketika saya bisa menggunakan ekspansi parameter ... Penyalahgunaan RE akan membuat skrip bash lebih lambat
F. Hauri
Jawaban diedit: Tidak perlu extglob(dan sedikit lebih cepat)!
F. Hauri
@CharlesDuffy, Pada pi raspberry saya, 1000 iterasi akan mengambil 2,5sec dengan versi saya dan 4,4sec dengan versi Anda!
F. Hauri
Tidak bisa berdebat dengan itu 👍
Charles Duffy
1

Untuk menangkap angka negatif:

if [[ $1 == ?(-)+([0-9.]) ]]
    then
    echo number
else
    echo not a number
fi
pengguna28490
sumber
Juga, ini membutuhkan globbing diperpanjang untuk diaktifkan terlebih dahulu. Ini adalah fitur Bash-only yang dinonaktifkan secara default.
tripleee
@tripleee extended globbing diaktifkan secara otomatis saat menggunakan == atau! = When the ‘==’ and ‘!=’ operators are used, the string to the right of the operator is considered a pattern and matched according to the rules described below in Pattern Matching, as if the extglob shell option were enabled. gnu.org/software/bash/manual/bashref.html#index-_005b_005b
Badr Elmers
@BadrElmers Terima kasih atas pembaruannya. Ini tampaknya menjadi perilaku baru yang tidak benar di Bash 3.2.57 saya (MacOS Mojave). Saya melihatnya berfungsi seperti yang Anda gambarkan dalam 4.4.
tripleee
1

Anda dapat menggunakan "biarkan" juga seperti ini:

[ ~]$ var=1
[ ~]$ let $var && echo "It's a number" || echo "It's not a number"
It\'s a number
[ ~]$ var=01
[ ~]$ let $var && echo "It's a number" || echo "It's not a number"
It\'s a number
[ ~]$ var=toto
[ ~]$ let $var && echo "It's a number" || echo "It's not a number"
It\'s not a number
[ ~]$ 

Tapi saya lebih suka menggunakan operator "= ~" Bash 3+ seperti beberapa jawaban di utas ini.

Idriss Neumann
sumber
5
Ini sangat berbahaya. Jangan mengevaluasi aritmatika yang tidak divalidasi dalam shell. Itu harus divalidasi dengan cara lain terlebih dahulu.
ormaaj
1
printf '%b' "-123\nABC" | tr '[:space:]' '_' | grep -q '^-\?[[:digit:]]\+$' && echo "Integer." || echo "NOT integer."

Hapus -\?pola pencocokan grep jika Anda tidak menerima bilangan bulat negatif.

Ane Dijitak
sumber
2
Downvote karena kurangnya penjelasan. Bagaimana cara kerjanya? Terlihat rumit dan rapuh, dan tidak jelas input apa yang akan diterima. (Misalnya, apakah menghilangkan spasi sangat penting? Mengapa? Ia akan mengatakan angka dengan ruang yang disematkan adalah angka yang valid, yang mungkin tidak diinginkan.)
tripleee
1

Melakukan hal yang sama di sini dengan ekspresi reguler yang menguji seluruh bagian dan bagian desimal, dipisahkan dengan titik.

re="^[0-9]*[.]{0,1}[0-9]*$"

if [[ $1 =~ $re ]] 
then
   echo "is numeric"
else
  echo "Naahh, not numeric"
fi
Jerome
sumber
Bisakah Anda menjelaskan mengapa jawaban Anda secara fundamental berbeda dari jawaban lama lainnya, misalnya, jawaban Charles Duffy? Yah, jawaban Anda sebenarnya rusak karena memvalidasi satu periode.
gniourf_gniourf
tidak yakin untuk memahami satu periode di sini ... itu adalah satu atau nol periode yang diharapkan .... Tapi benar tidak ada yang berbeda secara mendasar, hanya menemukan regex lebih mudah dibaca.
Jerome
juga menggunakan * harus cocok dengan lebih banyak kasus dunia nyata
Jerome
Masalahnya adalah Anda mencocokkan string kosong a=''dan string yang hanya berisi titik a='.'sehingga kode Anda agak rusak ...
gniourf_gniourf
0

Saya menggunakan yang berikut (untuk bilangan bulat):

## ##### constants
##
## __TRUE - true (0)
## __FALSE - false (1)
##
typeset -r __TRUE=0
typeset -r __FALSE=1

## --------------------------------------
## isNumber
## check if a value is an integer 
## usage: isNumber testValue 
## returns: ${__TRUE} - testValue is a number else not
##
function isNumber {
  typeset TESTVAR="$(echo "$1" | sed 's/[0-9]*//g' )"
  [ "${TESTVAR}"x = ""x ] && return ${__TRUE} || return ${__FALSE}
}

isNumber $1 
if [ $? -eq ${__TRUE} ] ; then
  print "is a number"
fi
Marnix
sumber
Hampir benar (Anda menerima string kosong) tetapi sangat rumit sampai-sampai kebingungan.
Gilles 'SANGAT berhenti menjadi jahat'
2
Salah: Anda menerima -n, dll. (Karena echo), dan Anda menerima variabel dengan mengikuti baris baru (karena $(...)). Dan omong-omong, printbukan perintah shell yang valid.
gniourf_gniourf
0

Saya mencoba resep ultrasawblade karena rasanya paling praktis bagi saya, dan tidak bisa membuatnya bekerja. Pada akhirnya saya menemukan cara lain, berdasarkan yang lain dalam penggantian parameter, kali ini dengan penggantian regex:

[[ "${var//*([[:digit:]])}" ]]; && echo "$var is not numeric" || echo "$var is numeric"

Ini menghapus setiap: digit: karakter kelas dalam $ var dan memeriksa apakah kita dibiarkan dengan string kosong, yang berarti bahwa aslinya hanya angka.

Yang saya sukai dari yang satu ini adalah footprint dan fleksibilitasnya yang kecil. Dalam bentuk ini hanya berfungsi untuk bilangan bulat basis 10 tanpa batas, meskipun tentunya Anda dapat menggunakan pencocokan pola yang sesuai dengan kebutuhan lain.

ata
sumber
Membaca solusi mrucci, tampilannya hampir sama dengan milik saya, tetapi menggunakan penggantian string biasa alih-alih "gaya sed". Keduanya menggunakan aturan yang sama untuk pencocokan pola dan, AFAIK, solusi yang dapat dipertukarkan.
ata
sedadalah POSIX, sedangkan solusi Anda adalah bash. Keduanya memiliki kegunaannya
v010dya
0

Cepat & Kotor: Saya tahu ini bukan cara yang paling elegan, tapi saya biasanya hanya menambahkan nol dan menguji hasilnya. seperti itu:

function isInteger {
  [ $(($1+0)) != 0 ] && echo "$1 is a number" || echo "$1 is not a number"
 }

x=1;      isInteger $x
x="1";    isInteger $x
x="joe";  isInteger $x
x=0x16 ;  isInteger $x
x=-32674; isInteger $x   

$ (($ 1 + 0)) akan mengembalikan 0 atau bom jika $ 1 BUKAN bilangan bulat. sebagai contoh:

function zipIt  { # quick zip - unless the 1st parameter is a number
  ERROR="not a valid number. " 
  if [ $(($1+0)) != 0 ] ; then  # isInteger($1) 
      echo " backing up files changed in the last $1 days."
      OUT="zipIt-$1-day.tgz" 
      find . -mtime -$1 -type f -print0 | xargs -0 tar cvzf $OUT 
      return 1
  fi
    showError $ERROR
}

CATATAN: Saya kira saya tidak pernah berpikir untuk memeriksa pelampung atau jenis campuran yang akan membuat seluruh skrip bom ... dalam kasus saya, saya tidak ingin itu berjalan lebih jauh. Saya akan bermain-main dengan solusi mrucci dan regex Duffy - mereka tampaknya paling kuat dalam kerangka bash ...

WWWIZARDS
sumber
4
Ini menerima ekspresi aritmatika seperti 1+1, tetapi menolak beberapa bilangan bulat positif dengan 0s (karena 08konstanta oktal tidak valid).
Gilles 'SANGAT berhenti menjadi jahat'
2
Ini menyebabkan masalah lain juga: 0bukan angka, dan tunduk pada kode injeksi sewenang-wenang, mencobanya: isInteger 'a[$(ls)]'. Ups.
gniourf_gniourf
1
Dan perluasan tanda $((...))kutip, angka IFS=123akan mengubahnya.
Isaac