Membandingkan bilangan bulat: ekspresi aritmatika atau ekspresi kondisional

20

Dalam Bash, dua bilangan bulat dapat dibandingkan menggunakan ekspresi kondisional

arg1 OP arg2

OP adalah salah satu -eq, -ne, -lt, -le, -gt, atau -ge. Operator biner aritmatika ini mengembalikan true jika arg1 sama dengan, tidak sama dengan, kurang dari, kurang dari atau sama dengan, lebih besar dari, atau lebih besar dari atau sama dengan arg2 , masing-masing. Arg1 dan arg2 mungkin bilangan bulat positif atau negatif.

atau ekspresi aritmatika:

<= >= < > perbandingan

== != persamaan dan ketidaksetaraan

Mengapa kita memiliki dua cara berbeda untuk membandingkan dua bilangan bulat? Kapan menggunakan yang mana?

Misalnya, [[ 3 -lt 2 ]]gunakan ekspresi kondisional, dan (( 3 < 2 ))gunakan ekspresi aritmatika. Keduanya mengembalikan 0 bila perbandingannya benar

Saat membandingkan dua bilangan bulat, dapatkah kedua metode ini selalu digunakan secara bergantian? Jika ya, mengapa Bash memiliki dua metode daripada satu?

Tim
sumber
1
= != < <= > >=bandingkan string . 1 -eq 01but 1 != 01and 8 -lt 42but8 > 42
dave_thompson_085
Mereka kelebihan dalam ekspresi aritmatika.
Tim
1
Anda harus mencari di bash changelogs untuk mengetahui kapan setiap fitur ditambahkan. Saya menduga ekspresi aritmatika ditambahkan lebih lambat daripada perintah tes.
glenn jackman
Saya tidak bertanya tentang membandingkan string. @muru.
Tim

Jawaban:

28

Ya, kami memiliki dua cara berbeda untuk membandingkan dua bilangan bulat.

Tampaknya fakta-fakta ini tidak diterima secara luas di forum ini:

  1. Di dalam idiom [ ]operator untuk perbandingan aritmatika adalah -eq, -ne, -lt, -le, -gtdan -ge.

    Karena mereka juga di dalam perintah uji dan di dalam a [[ ]].

    Ya dalam idiom ini, =, <, dll operator tali.

  2. Di dalam idiom (( ))operator untuk perbandingan aritmatika adalah ==, !=, <, <=, >, dan >=.

    Tidak, ini bukan "ekspansi aritmatika" (yang dimulai dengan a $) sebagai $(( )). Ini didefinisikan sebagai "Perintah Majemuk" di man bash.

    Ya, ia mengikuti aturan yang sama (secara internal) dari "ekspansi aritmatika" tetapi tidak memiliki output, hanya nilai keluar. Bisa digunakan seperti ini:

if (( 2 > 1 )); then ...

Mengapa kita memiliki dua cara berbeda untuk membandingkan dua bilangan bulat?

Saya kira yang terakhir (( ))dikembangkan sebagai cara yang lebih sederhana untuk melakukan tes aritmatika. Ini hampir sama dengan $(( ))tetapi tidak memiliki output.

Mengapa dua? Yah sama seperti mengapa kita memiliki dua printf(eksternal dan builtin) atau empat tes (eksternal test, builtin test, [dan [[). Itulah cara kerang tumbuh, memperbaiki beberapa area dalam satu tahun, meningkatkan beberapa lainnya di tahun berikutnya.

Kapan menggunakan yang mana?

Itu pertanyaan yang sangat sulit karena seharusnya tidak ada perbedaan yang efektif. Tentu saja ada beberapa perbedaan dalam cara [ ]kerja dan (( ))kerja secara internal, tetapi: mana yang lebih baik untuk membandingkan dua bilangan bulat? Siapa saja!

Saat membandingkan dua bilangan bulat, dapatkah kedua metode ini selalu digunakan secara bergantian?

Untuk dua angka saya terpaksa mengatakan ya.
Tetapi untuk variabel, ekspansi, operasi matematika mungkin ada perbedaan utama yang harus menguntungkan satu atau yang lain. Saya tidak bisa mengatakan bahwa keduanya sama. Untuk satu, (( ))dapat melakukan beberapa operasi matematika secara berurutan:

if (( a=1, b=2, c=a+b*b )); then echo "$c"; fi

Jika ya, mengapa Bash memiliki dua metode daripada satu?

Jika keduanya membantu, mengapa tidak?

Yurij Goncharuk
sumber
1
=adalah tugas dan ==merupakan perbandingan dalam ekspansi aritmatika. Pertanyaannya mengutip dengan benar. Tapi jawabannya salah.
ceving
12

Secara historis, testperintah itu ada terlebih dahulu (setidaknya sejauh Unix Seventh Edition pada 1979). Ini digunakan operator =dan !=untuk membandingkan string, dan -eq, -ne, -lt, dll untuk membandingkan angka. Misalnya, test 0 = 00itu salah, tetapi test 0 -eq 00itu benar. Saya tidak tahu mengapa sintaks ini dipilih, tetapi mungkin untuk menghindari menggunakan <dan >, yang shell akan diuraikan sebagai operator pengalihan. The testperintah mendapat sintaks lain beberapa tahun kemudian: [ … ]setara dengan test ….

The [[ … ]]sintaks kondisional, dalam yang <dan >dapat digunakan sebagai operator tanpa mengutip, ditambahkan kemudian, di ksh. Itu tetap kompatibilitas dengan [ … ], jadi itu menggunakan operator yang sama, tetapi ditambahkan <dan >untuk membandingkan string (misalnya, [[ 9 > 10 ]]tetapi [[ 9 -lt 10 ]]). Untuk informasi lebih lanjut, lihat menggunakan braket tunggal atau ganda - bash

Ekspresi aritmatika juga datang lebih lambat dari testperintah, di kulit Korn , pada suatu waktu di tahun 1980-an. Mereka mengikuti sintaks bahasa C, yang sangat populer di kalangan Unix. Jadi mereka menggunakan operator C: ==untuk persamaan, <=untuk kurang-atau-sama, dll.

Unix Seventh Edition tidak memiliki ekspresi aritmatika, tetapi memang memiliki exprperintah , yang juga menerapkan sintaks mirip C untuk operasi integer, termasuk operator pembandingnya. Dalam skrip shell, karakter <dan >harus dikutip untuk melindunginya dari shell, misalnya if expr 1 \< 2; …setara dengan if test 1 -lt 2; …. Penambahan ekspresi aritmatika ke shell memanfaatkan sebagian besar exprusang, sehingga tidak terkenal hari ini.

Dalam skrip sh, Anda biasanya akan menggunakan ekspresi aritmatika untuk menghitung nilai integer, dan [ … ]membandingkan integer.

if [ "$((x + y))" -lt "$z" ]; then 

Dalam skrip ksh, bash, atau zsh, Anda dapat menggunakan ((…))keduanya.

if ((x + y < z)); then 

The [[ … ]]Bentuk berguna jika Anda ingin menggunakan conditional melibatkan hal-hal lain selain bilangan bulat.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
1

Menurut halaman manual pengujian, = dan! = Digunakan untuk perbandingan string sedangkan ekspresi -eq, -gt, -lt, -ge, -le, dan -ne adalah perbandingan integer. Saya selalu mengikuti konvensi ini ketika menulis skrip shell dan selalu berhasil. Perlu diketahui bahwa jika Anda memiliki variabel dalam ekspresi, Anda mungkin perlu mengutip variabel dalam beberapa cara untuk menghindari melakukan perbandingan nol.

Di atas kertas, kami melakukan perbandingan string / angka tanpa banyak berpikir. Komputer di sisi lain tidak tahu apakah 987 adalah angka atau serangkaian karakter. Anda memerlukan operator yang berbeda untuk memberi tahu komputer apa yang harus dilakukan sehingga Anda mendapatkan hasil yang benar. Ada beberapa info tambahan di sini yang menjelaskan beberapa sejarah. Pada dasarnya, variabel tidak diketik dan tetap seperti itu untuk kompatibilitas historis.

signal7
sumber
Dalam posting saya, = dan !=operator aritmatika, sedangkan halaman manual testhanya menunjukkan operator ekspresi kondisional.
Tim