Perbedaan antara let, expr, dan $ []

23

Saya ingin tahu apa perbedaan sebenarnya

a=$[1+1]
a=$((1+1))
let a=1+1
a=$(expr 1 + 1 )

Semua 4 menetapkan variabel a dengan 2, tetapi apa bedanya?

Dari apa yang saya temukan sejauh ini, adalah bahwa expr lebih lambat karena itu bukan shell builtin yang sebenarnya. Tapi tidak lebih dari itu.

ADDB
sumber

Jawaban:

25

Semua ini berhubungan dengan aritmatika, tetapi dengan cara yang berbeda dan variabel dibuat melalui cara yang berbeda. Beberapa di antaranya khusus untuk bashkerang, sementara yang lain tidak.

  • $((...))disebut ekspansi aritmatika , yang merupakan ciri khas dari bashdan kshkerang. Ini memungkinkan melakukan aritmatika integer sederhana , tidak ada hal-hal floating point sekalipun. Hasil ekspresi menggantikan ekspresi, seperti yang echo $((1+1))akan terjadiecho 2
  • ((...))disebut sebagai evaluasi aritmatika dan dapat digunakan sebagai bagian dari if ((...)); thenatau while ((...)) ; dopernyataan. Ekspansi ekspansi aritmatika $((..))menggantikan output operasi dan dapat digunakan untuk menetapkan variabel seperti i=$((i+1))tetapi tidak dapat digunakan dalam pernyataan bersyarat.
  • $[...] adalah sintaks lama untuk ekspansi aritmatika yang sudah usang. Lihat juga . Ini kemungkinan disimpan agar bashskrip lama tidak rusak. Ini tidak berhasil ksh93, jadi dugaan saya adalah sintaks ini khusus untuk bash. CATATAN : spasi sangat penting di sini; jangan bingung $[1+1]dengan hal-hal seperti [ $a -eq $b ]. The [dengan spasi dikenal sebagai testperintah, dan Anda biasanya melihatnya di bagian pengambilan keputusan. Sangat berbeda dalam perilaku dan tujuan.
  • letadalah kata kunci bashdan kshyang memungkinkan untuk pembuatan variabel dengan evaluasi aritmatika sederhana. Jika Anda mencoba untuk menetapkan string di sana seperti let a="hello world"Anda akan mendapatkan kesalahan sintaksis. Bekerja di bashdan ksh93.
  • $(...)adalah substitusi perintah, di mana Anda benar-benar mengambil output dari perintah dan menetapkan ke variabel. Perintah Anda di sini adalah expr, yang mengambil argumen posisi, seperti expr arg1 arg2 arg3, jadi spasi adalah penting. Ini semacam kalkulator baris perintah kecil untuk aritmatika bilangan bulat, ditambah beberapa jenis true / false dan regex. Ini adalah perintah shell-neutral.

Perlu juga dicatat bahwa ekspansi aritmatika dan penggantian perintah ditentukan oleh standar POSIX , sementara letdan $[...]tidak.

Sergiy Kolodyazhnyy
sumber
1
((...))sebenarnya dapat digunakan untuk penugasan bash, kshdan zsh: n=10; ((n+=10)); echo $nmencetak 20 dan ((x=1)); echo $xmencetak 1.
Alexej Magura
1
@Alexej Terima kasih. Jawaban diperbarui, bagian itu dihapus
Sergiy Kolodyazhnyy
11
  • letperintah melakukan evaluasi aritmatika dan shell built-in.

    • Jalankan perintah ini dan Anda tidak mendapatkan apa-apa (hanya mengevaluasi):

      let 1+2
  • $(( ))digunakan untuk melakukan ekspansi aritmatika : baca di sini

    • Jalankan yang ini dan Anda akan mendapatkan kesalahan (karena ekspansi):

      $((1+2))
  • $[ ] adalah sintaks lama untuk ekspansi aritmatika:

    Format lama $ [ekspresi] sudah usang dan akan dihapus pada bash mendatang. Bash Man Page

  • expr adalah perintah biner, jika Anda ingin melakukan ekspansi aritmatika dalam subsituasi perintah, Anda dapat menggunakannya:

    echo $(expr 1 + 2) 
    echo `expr 1 + 2`
Ravexina
sumber
4

Karena beberapa jawaban di atas secara khusus menyebutkan ksh93perlu dicatat bahwa ia dapat melakukan matematika titik mengambang, misalnya:

$ print $((1.0/3)) 
0.333333333333333333

Anda dapat mengontrol ketepatan output dengan printf, misalnya:

$ printf "%.4f\n" $((1.0/3))
0.3333

Setidaknya satu argumen harus ditentukan sebagai angka titik-mengambang seperti di atas. Jika keduanya ditentukan sebagai bilangan bulat maka hanya matematika bilangan bulat yang dilakukan, misalnya:

$ print $((1/3))  
0

Ini bisa membantu ketika Anda membutuhkan matematika floating point dalam skrip shell karena Anda dapat menghindari memanggil perintah eksternal.

bersin
sumber
Terjadi pada saya bahwa Anda mungkin tertarik untuk mengirim jawaban ke Dapatkah saya menggunakan pecahan / desimal dalam skrip bash? Meskipun judul, saya pikir konteksnya membuat jelas bahwa kerang Bourne-gaya lainnya yang relevan, yang mengapa saya posting sebuah zshjawaban . Karena kshdan bashlebih mirip satu sama lain (secara umum) daripada keduanya zsh, menurut saya kh93jawaban berbasis pertanyaan itu bisa sangat berguna.
Eliah Kagan
1

lettidak bekerja di cron. Saya pikir itu karena letmemiliki lingkungannya sendiri. Gunakan $((...))karena itu POSIX. Sebagai contoh,

let x=1+2
echo x=$x

di cron, menghasilkan "x =", tetapi "x = 3" saat dijalankan dari shell.

x=$((1+2))
echo x=$x

menghasilkan "x = 3" dalam semua kasus.

SparkEV
sumber