Bagaimana cara menambahkan variabel dalam bash?


609

Saya telah mencoba untuk meningkatkan variabel numerik menggunakan keduanya var=$var+1dan var=($var+1)tidak berhasil. Variabelnya adalah angka, meskipun bash tampaknya membacanya sebagai string.

Bash versi 4.2.45 (1) -release (x86_64-pc-linux-gnu) di Ubuntu 13.10.

Jawaban:


948

Ada lebih dari satu cara untuk meningkatkan variabel dalam bash, tetapi apa yang Anda coba tidak benar.

Anda dapat menggunakan misalnya ekspansi aritmatika :

var=$((var+1))
((var=var+1))
((var+=1))
((var++))

Atau Anda dapat menggunakan let:

let "var=var+1"
let "var+=1"
let "var++"

Lihat juga: http://tldp.org/LDP/abs/html/dblparens.html .


31
atau ((++var))atau ((var=var+1))atau ((var+=1)).
gniourf_gniourf

6
Anehnya, var=0; ((var++))mengembalikan kode kesalahan sementara var=0; ((var++)); ((var++))tidak. Ada yang tahu kenapa?
phunehehe

15
@ phunehehe Lihatlah help '(('. Baris terakhir berbunyi:Returns 1 if EXPRESSION evaluates to 0; returns 0 otherwise.
Radu Rădeanu

2
Saya menduga evaluasi nol seperti 1mengapa tip @ gniourf_gniourf termasuk ((++var))tetapi tidak ((var++)).
DreadPirateShawn

4
apakah aman digunakan let var++, tanpa tanda kutip?
wjandrea

161
var=$((var + 1))

Aritmatika dalam bash menggunakan $((...))sintaks.


9
Jauh lebih baik dari jawaban yang diterima. Hanya dalam ruang 10%, Anda berhasil memberikan contoh yang cukup (satu banyak - sembilan berlebihan sampai saat Anda hanya pamer), dan Anda memberikan kami info yang cukup untuk mengetahui bahwa ((...))itulah kunci untuk menggunakan aritmatika di bash. Saya tidak menyadari bahwa hanya dengan melihat jawaban yang diterima - saya pikir ada seperangkat aturan aneh tentang urutan operasi atau sesuatu yang mengarah ke semua tanda kurung dalam jawaban yang diterima.
ArtOfWarfare

82

Analisis Kinerja dari berbagai opsi

Berkat jawaban Radu Rădeanu yang menyediakan cara-cara berikut untuk meningkatkan variabel dalam bash:

var=$((var+1))
((var=var+1))
((var+=1))
((var++))
let "var=var+1"
let "var+=1" 
let "var++"

Ada beberapa cara lain juga. Misalnya, lihat jawaban lain untuk pertanyaan ini.

let var++
var=$((var++))
((++var))
{
    declare -i var
    var=var+1
    var+=1
}
{
    i=0
    i=$(expr $i + 1)
}

Memiliki begitu banyak opsi mengarah pada dua pertanyaan ini:

  1. Apakah ada perbedaan kinerja di antara mereka?
  2. Jika demikian, mana yang berkinerja terbaik?

Kode uji kinerja tambahan:

#!/bin/bash

# To focus exclusively on the performance of each type of increment
# statement, we should exclude bash performing while loops from the
# performance measure. So, let's time individual scripts that
# increment $i in their own unique way.

# Declare i as an integer for tests 12 and 13.
echo > t12 'declare -i i; i=i+1'
echo > t13 'declare -i i; i+=1'
# Set i for test 14.
echo > t14 'i=0; i=$(expr $i + 1)'

x=100000
while ((x--)); do
    echo >> t0 'i=$((i+1))'
    echo >> t1 'i=$((i++))'
    echo >> t2 '((i=i+1))'
    echo >> t3 '((i+=1))'
    echo >> t4 '((i++))'
    echo >> t5 '((++i))'
    echo >> t6 'let "i=i+1"'
    echo >> t7 'let "i+=1"'
    echo >> t8 'let "i++"'
    echo >> t9 'let i=i+1'
    echo >> t10 'let i+=1'
    echo >> t11 'let i++'
    echo >> t12 'i=i+1'
    echo >> t13 'i+=1'
    echo >> t14 'i=$(expr $i + 1)'
done

for script in t0 t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14; do
    line1="$(head -1 "$script")"
    printf "%-24s" "$line1"
    { time bash "$script"; } |& grep user
    # Since stderr is being piped to grep above, this will confirm
    # there are no errors from running the command:
    eval "$line1"
    rm "$script"
done

Hasil:

i=$((i+1))              user    0m0.992s
i=$((i++))              user    0m0.964s
((i=i+1))               user    0m0.760s
((i+=1))                user    0m0.700s
((i++))                 user    0m0.644s
((++i))                 user    0m0.556s
let "i=i+1"             user    0m1.116s
let "i+=1"              user    0m1.100s
let "i++"               user    0m1.008s
let i=i+1               user    0m0.952s
let i+=1                user    0m1.040s
let i++                 user    0m0.820s
declare -i i; i=i+1     user    0m0.528s
declare -i i; i+=1      user    0m0.492s
i=0; i=$(expr $i + 1)   user    0m5.464s

Kesimpulan:

Tampaknya bash lebih cepat dalam performanya i+=1ketika $idinyatakan sebagai integer. letpernyataan tampaknya sangat lambat, dan exprsejauh ini paling lambat karena bukan builtin.


Rupanya kecepatan berkorelasi dengan panjang perintah. Saya bertanya-tanya apakah perintah memanggil fungsi yang sama.
MatthewRock

18

Ada juga ini:

var=`expr $var + 1`

Perhatikan spasi dan juga ' tidak '

Sementara jawaban Radu, dan komentarnya, lengkap dan sangat membantu, mereka spesifik bash. Saya tahu Anda secara khusus bertanya tentang bash, tapi saya pikir saya akan menjawab karena saya menemukan pertanyaan ini ketika saya mencari untuk melakukan hal yang sama menggunakan sh di busybox di bawah uCLinux. Portable ini melampaui bash.


1
Anda juga dapat menggunakani=$((i+1))
wjandrea

Jika proses substitusi $(...)tersedia pada shell ini, saya akan merekomendasikan menggunakannya sebagai gantinya.
Radon Rosborough


7

Ada satu metode yang hilang dalam semua jawaban - bc

$ VAR=7    
$ bc <<< "$VAR+2"
9
$ echo $VAR
7
$ VAR=$( bc <<< "$VAR+1" )
$ echo $VAR
8

bcditentukan oleh standar POSIX , jadi harus ada pada semua versi Ubuntu dan sistem yang mendukung POSIX . The <<<redirection dapat diubah untuk echo "$VAR" | bcuntuk portabilitas, tapi karena pertanyaan bertanya tentang bash- itu OK untuk hanya menggunakan <<<.


6

Kode kembali 1masalah hadir untuk semua varian default ( let, (()), dll). Ini sering menyebabkan masalah, misalnya, dalam skrip yang digunakan set -o errexit. Inilah yang saya gunakan untuk mencegah kode kesalahan 1dari ekspresi matematika yang mengevaluasi 0;

math() { (( "$@" )) || true; }

math a = 10, b = 10
math a++, b+=2
math c = a + b
math mod = c % 20
echo $a $b $c $mod
#11 12 23 3

0

Ini harus menjadi cara terburuk untuk menyelesaikan tugas semudah itu, tetapi saya hanya ingin mendokumentasikannya untuk bersenang-senang (kira-kira berlawanan dengan kode golf).

$ var=0
$ echo $var
0
$ var="$(python -c 'print('$var'+1)')"
$ echo $var
1

atau

$ var="$(printf '%s\n' $var'+1' | bc)"
$ echo $var
1

Serius gunakan salah satu pilihan lain yang jauh lebih baik di sini.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.