Pertanyaan Bagaimana cara menaikkan variabel dalam bash?


Saya telah mencoba menaikkan suatu variabel numerik menggunakan keduanya var=$var+1 dan var=($var+1) tanpa keberhasilan. Variabel adalah angka, meskipun bash tampaknya membacanya sebagai string.

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


455
2017-12-03 16:34


asal




Jawaban:


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

Anda bisa menggunakan misalnya ekspansi aritmatika:

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

Atau Anda bisa menggunakannya let:

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

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


720
2017-12-03 16:39



atau ((++var)) atau ((var=var+1)) atau ((var+=1)). - gniourf_gniourf
atau var = $ (expr $ var + 1) - Javier López
Anehnya, var=0; ((var++)) mengembalikan kode kesalahan saat var=0; ((var++)); ((var++)) tidak. Ada yang tahu kenapa? - phunehehe
@phunehehe Lihat help '(('. Baris terakhir mengatakan: Returns 1 if EXPRESSION evaluates to 0; returns 0 otherwise. - Radu Rădeanu
Apakah ini aman untuk digunakan let var++, tanpa tanda kutip? - wjandrea


var=$((var + 1))

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


101
2017-12-03 16:38



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


Analisis Kinerja berbagai opsi

Terimakasih untuk Jawaban Radu Rădeanu yang menyediakan cara-cara berikut untuk menaikkan variabel dalam bash:

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

Ada cara lain juga. Sebagai contoh, lihat jawaban lain pada pertanyaan ini.

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

Memiliki begitu banyak pilihan mengarah pada dua pertanyaan berikut:

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

Kode pengujian 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 paling cepat tampil i+=1 kapan $i dinyatakan sebagai integer. let pernyataan tampak sangat lambat, dan expr sejauh ini yang paling lambat karena itu bukan builtin.


62
2017-07-31 17:15



Rupanya kecepatan berkorelasi dengan panjang perintah. Saya bertanya-tanya apakah perintah memanggil fungsi yang sama. - MatthewRock
i=(expr ...) adalah kesalahan sintaks. Apakah yang kamu maksud i=$(expr ...)? - muru
@muru diperbaiki, dan ditambahkan cek ke dalam for loop. - wjandrea


Ada juga ini:

var=`expr $var + 1`

Perhatikan dengan cermat ruang-ruang dan juga ` tidak '

Sementara jawaban Radu, dan komentar-komentarnya, lengkap dan sangat membantu, itu spesifik sekali. Saya tahu Anda secara khusus bertanya tentang bash, tapi saya pikir saya akan masuk karena saya menemukan pertanyaan ini ketika saya ingin melakukan hal yang sama menggunakan sh di busybox di bawah uCLinux. Ini portabel di luar bash.


14
2017-08-22 23:11



Anda juga bisa menggunakan i=$((i+1)) - wjandrea
Jika substitusi proses $(...) tersedia di shell ini, saya sarankan untuk menggunakannya. - Radon Rosborough


Jika Anda menyatakan $var sebagai bilangan bulat, maka apa yang Anda coba pertama kali akan benar-benar berfungsi:

$ declare -i var=5
$ echo $var
5
$ var=$var+1
$ echo $var
6

Referensi: Jenis variabel, Panduan Bash untuk Pemula


9
2017-12-06 22:19





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

bc ditentukan oleh POSIX standar, jadi harus ada pada semua versi sistem yang kompatibel dengan Ubuntu dan POSIX. Itu <<< pengarahan ulang bisa diubah menjadi echo "$VAR" | bc untuk portabilitas, tetapi karena pertanyaan itu bertanya tentang bash - Tidak apa-apa hanya menggunakan <<<.


6
2018-02-23 13:58





Kode kembali 1 masalah 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 1 dari ekspresi matematika yang dievaluasi 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

4