Bagaimana saya bisa menambahkan angka dalam skrip Bash?

567

Saya punya skrip Bash ini dan saya punya masalah di baris 16. Bagaimana saya bisa mengambil hasil sebelumnya dari baris 15 dan menambahkannya ke variabel di baris 16?

#!/bin/bash

num=0
metab=0

for ((i=1; i<=2; i++)); do
    for j in `ls output-$i-*`; do
        echo "$j"

        metab=$(cat $j|grep EndBuffer|awk '{sum+=$2} END { print sum/120}') (line15)
        num= $num + $metab   (line16)
    done
    echo "$num"
 done
Nick
sumber
2
Saya pikir Anda akan mencetak nilai nol bahkan menggunakan jawaban berikut. Ada trik, misalnya proses substitusi, untuk membawa nilai akhir "inside num" menjadi "outside num".
Scott Chu

Jawaban:

977

Untuk bilangan bulat :

  • Gunakan ekspansi aritmatika :$((EXPR))

    num=$((num1 + num2))
    num=$(($num1 + $num2))       # Also works
    num=$((num1 + 2 + 3))        # ...
    num=$[num1+num2]             # Old, deprecated arithmetic expression syntax
  • Menggunakan exprutilitas eksternal . Perhatikan bahwa ini hanya diperlukan untuk sistem yang benar-benar lama.

    num=`expr $num1 + $num2`     # Whitespace for expr is important

Untuk floating point :

Bash tidak secara langsung mendukung ini, tetapi ada beberapa alat eksternal yang dapat Anda gunakan:

num=$(awk "BEGIN {print $num1+$num2; exit}")
num=$(python -c "print $num1+$num2")
num=$(perl -e "print $num1+$num2")
num=$(echo $num1 + $num2 | bc)   # Whitespace for echo is important

Anda juga dapat menggunakan notasi ilmiah (misalnya, 2.5e+2).


Perangkap umum :

  • Saat mengatur variabel, Anda tidak dapat memiliki spasi putih di kedua sisi =, jika tidak maka akan memaksa shell untuk menafsirkan kata pertama sebagai nama aplikasi yang akan dijalankan (misalnya, num=atau num)

    num= 1 num =2

  • bcdan exprmengharapkan setiap angka dan operator sebagai argumen terpisah, jadi spasi putih itu penting. Mereka tidak dapat memproses argumen seperti 3+ +4.

    num=`expr $num1+ $num2`

Karoly Horvath
sumber
1
Dalam jawaban pertama, ia mencetak saya expr: argumen non-numerik Yang kedua tidak berfungsi ..
Nick
1
@Nick: Apakah Anda mencoba ini sementara variabel bernama num1dan num2ada dan memiliki nilai integer?
sorpigal
1
Ya mereka ada tetapi satu variabel ganda .. apakah itu masalah ??
Nick
2
Ya, itu masalah :) Catatan: $((..))evaluasi aritmatika dijalankan dalam bash. exprdieksekusi sebagai proses terpisah, jadi itu akan jauh lebih lambat. gunakan yang terakhir pada sistem di mana evaluasi arithemtic tidak didukung (sh! = bash)
Karoly Horvath
4
Karena $((…))sudah distandarisasi oleh POSIX, itu harus menjadi semakin langka yang exprdiperlukan.
chepner
115

Gunakan $(( ))ekspansi aritmatika.

num=$(( $num + $metab ))

Lihat Bab 13. Perluasan Aritmatika untuk informasi lebih lanjut.

Steve Prentice
sumber
2
Aneh. Tidak berfungsi di sini ketika saya mencoba menghitung 191.003 + 190.
Sigur
2
Tidak berfungsi untuk angka dengan titik desimal.
fivedogit
30

Ada seribu satu cara untuk melakukannya. Inilah yang menggunakan dc(kalkulator meja reverse-polish yang mendukung aritmatika presisi tak terbatas):

dc <<<"$num1 $num2 + p"

Tetapi jika itu terlalu bash-y untuk Anda (atau masalah portabilitas) Anda bisa mengatakannya

echo $num1 $num2 + p | dc

Tapi mungkin Anda salah satu dari orang-orang yang berpikir RPN itu menjijikkan dan aneh; jangan khawatir! bcada di sini untuk Anda:

bc <<< "$num1 + $num2"
echo $num1 + $num2 | bc

Karena itu, ada beberapa peningkatan yang tidak terkait yang bisa Anda lakukan pada skrip Anda:

#!/bin/bash

num=0
metab=0

for ((i=1; i<=2; i++)); do
    for j in output-$i-* ; do # 'for' can glob directly, no need to ls
            echo "$j"

             # 'grep' can read files, no need to use 'cat'
            metab=$(grep EndBuffer "$j" | awk '{sum+=$2} END { print sum/120}')
            num=$(( $num + $metab ))
    done
    echo "$num"
done

Seperti yang dijelaskan dalam Bash FAQ 022 , Bash tidak secara asli mendukung angka floating point. Jika Anda perlu menjumlahkan angka floating point diperlukan penggunaan alat eksternal (suka bcatau dc).

Dalam hal ini solusinya adalah

num=$(dc <<<"$num $metab + p")

Untuk menambahkan akumulasi angka-angka yang mungkin mengambang ke num.

sorpigal
sumber
1
@ Kaligal Terima kasih banyaksss. Bisakah saya bertanya sesuatu yang lain..bagaimana saya bisa mencetak pada akhirnya bukan num tetapi num / 10 ??
Nick
23

Di bash,

 num=5
 x=6
 (( num += x ))
 echo $num   # ==> 11

Perhatikan bahwa bash hanya dapat menangani bilangan bulat aritmatika, jadi jika perintah awk Anda mengembalikan sebagian, maka Anda ingin mendesain ulang: inilah kode Anda yang ditulis ulang sedikit untuk mengerjakan semua matematika dalam awk.

num=0
for ((i=1; i<=2; i++)); do      
    for j in output-$i-*; do
        echo "$j"
        num=$(
           awk -v n="$num" '
               /EndBuffer/ {sum += $2}
               END {print n + (sum/120)}
           ' "$j"
        )
    done
    echo "$num"
done
glenn jackman
sumber
20

Saya selalu lupa sintaksnya jadi saya datang ke google, tetapi kemudian saya tidak pernah menemukan yang saya kenal: P. Ini adalah yang terbersih bagi saya dan lebih sesuai dengan apa yang saya harapkan dalam bahasa lain.

i=0
((i++))

echo $i;
ssshake
sumber
18
 #!/bin/bash
read X
read Y
echo "$(($X+$Y))"
Amarjeet Singh
sumber
1
Bekerja dengan baik di macOS.
Tmx
15

Saya sangat suka metode ini juga, kurang berantakan:

count=$[count+1]
unixball
sumber
1
Ngomong-ngomong, mengapa ini berhasil? Bagaimana kita menyebutnya? Saya tidak dapat menemukan dokumen tentang ini.
skyline75489
4
Lebih sedikit kekacauan, tetapi usang.
Camille Goudeseune
7

Cara lain yang POSIXsesuai portabel untuk dilakukan bash, yang dapat didefinisikan sebagai fungsi .bashrcuntuk semua operator aritmatika kenyamanan.

addNumbers () {
    local IFS='+'
    printf "%s\n" "$(( $* ))"
}

dan sebut saja di baris perintah sebagai,

addNumbers 1 2 3 4 5 100
115

Idenya adalah menggunakan Input-Field-Separator (IFS) , variabel khusus yang bashdigunakan untuk pemisahan kata setelah ekspansi dan untuk memecah baris menjadi kata-kata. Fungsi ini mengubah nilai secara lokal untuk menggunakan karakter pemisah kata sebagai operator penjumlahan +.

Ingat IFSini diubah secara lokal dan TIDAK berpengaruh pada IFSperilaku default di luar lingkup fungsi. Kutipan dari man bashhalaman,

Shell memperlakukan setiap karakter IFS sebagai pembatas, dan membagi hasil ekspansi lainnya menjadi kata-kata pada karakter ini. Jika IFS tidak disetel, atau nilainya tepat, default, lalu urutan,, dan pada awal dan akhir hasil ekspansi sebelumnya diabaikan, dan setiap urutan karakter IFS tidak pada awal atau akhir berfungsi untuk membatasi kata-kata.

The "$(( $* ))"mewakili daftar argumen dilewatkan menjadi terbelah oleh +dan kemudian nilai sum adalah output menggunakan printffungsi. Fungsi ini dapat diperluas untuk menambah ruang lingkup untuk operasi aritmatika lainnya juga.

Inian
sumber
2
#!/bin/bash

num=0
metab=0

for ((i=1; i<=2; i++)); do      
    for j in `ls output-$i-*`; do
        echo "$j"

        metab=$(cat $j|grep EndBuffer|awk '{sum+=$2} END { print sum/120}') (line15)
        let num=num+metab (line 16)
    done
    echo "$num"
done
Milen John Thomas
sumber