Bash betiğine nasıl sayı ekleyebilirim?


566

Bu Bash komut dosyası var ve 16 satırında bir sorun vardı. Nasıl satır 15 önceki sonucunu almak ve satır 16 değişkenine ekleyebilirsiniz?

#!/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

2
Aşağıdaki cevabı kullanarak bile sıfır değeri basacağınızı düşünüyorum. "İç num" in son değerini "dış num" a getirmek için bir numara var, örneğin işlem bölümü.
Scott Chu

Yanıtlar:


975

Tamsayılar için :

  • Aritmetik genişletmeyi kullanın :$((EXPR))

    num=$((num1 + num2))
    num=$(($num1 + $num2))       # Also works
    num=$((num1 + 2 + 3))        # ...
    num=$[num1+num2]             # Old, deprecated arithmetic expression syntax
  • Harici expryardımcı programı kullanma . Bunun yalnızca eski sistemler için gerekli olduğunu unutmayın.

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

Kayan nokta için :

Bash bunu doğrudan desteklemez, ancak kullanabileceğiniz birkaç harici araç vardır:

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

Bilimsel gösterimi de kullanabilirsiniz (örneğin, 2.5e+2).


Yaygın tuzaklar :

  • Bir değişken ayarlarken, her iki tarafında boşluk bırakamazsınız =, aksi takdirde kabuğu ilk kelimeyi çalışacak uygulamanın adı olarak yorumlamaya zorlar (örneğin, num=veya num)

    num= 1 num =2

  • bcve exprher bir sayıyı ve operatörü ayrı bir argüman olarak bekliyoruz, bu nedenle boşluk önemlidir. Gibi argümanları işleyemezler 3+ +4.

    num=`expr $num1+ $num2`


1
İlk cevapta beni ifade yazdırıyor: sayısal olmayan argüman İkincisi çalışmıyor ..
Nick

1
@Nick: Değişkenler adlandırılmış num1ve varken num2ve tamsayı değerleri varken bunu denediniz mi ?
sorpigal

1
Evet onlar var ama tek değişken çift .. bu bir sorun mu?
Nick

2
Evet, bu bir sorun :) Not: $((..))aritmetik değerlendirme bash içinde gerçekleştirilir. exprayrı bir işlem olarak yürütülür, bu yüzden çok daha yavaş olacaktır. ikincisini aritmetik değerlendirmenin desteklenmediği sistemlerde kullanın (sh! = bash)
Karoly Horvath

4
Yana $((…))POSIX tarafından standardize edilmiştir, o kadar giderek nadir haline gelmelidir exprgereklidir.
chepner

115

$(( ))Aritmetik genişletmeyi kullanın .

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

Daha fazla bilgi için Bölüm 13'e bakın .


2
Garip. Hesaplamaya çalıştığımda burada çalışmıyor 191.003 + 190.
Sigur

2
Ondalık noktalı sayılar için çalışmaz.
fivedogit

30

Bunu yapmak için bin ve bir yol var. İşte bir dc(sınırsız hassas aritmetiği destekleyen ters cilalı bir masa hesap makinesi):

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

Ancak bu sizin için çok bash-y ise (veya taşınabilirlik önemlidir)

echo $num1 $num2 + p | dc

Ama belki de RPN'in yapışkan ve garip olduğunu düşünen insanlardan birisiniz; endişelenme! bcsenin için burada:

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

Bununla birlikte, senaryonuzda yapabileceğiniz bazı alakasız iyileştirmeler var:

#!/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

Bash SSS 022'de açıklandığı gibi , Bash kayan nokta numaralarını yerel olarak desteklemez. Kayan nokta sayılarını toplamanız gerekiyorsa harici bir aracın kullanımı ( bcveyadc ) kullanılması gerekir.

Bu durumda çözüm

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

Eklemek için muhtemelen kayan nokta sayıları biriktirin num.


1
@Sorpigal Teşekkürler çok .. Sana başka bir şey sorabilir miyim .. sonunda num değil num / 10 nasıl yazdırabilirim ??
Nick

23

Bash'da,

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

Bash'ın tamsayı aritmetiğini işleyebileceğini unutmayın, bu nedenle awk komutunuz bir kesir döndürürse, yeniden tasarlamak isteyeceksiniz: işte kodunuz awk'de tüm matematiği yapmak için biraz yeniden yazılmıştır.

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

20

Sözdizimini her zaman unuturum, bu yüzden google'a geliyorum, ama sonra tanıdığım birini asla bulamıyorum: P. Bu benim için en temiz ve diğer dillerde beklediğim şeyler için daha doğru.

i=0
((i++))

echo $i;


15

Ben de bu yöntemi seviyorum, daha az dağınıklık:

count=$[count+1]

1
Bu arada neden çalışıyor? Buna nasıl denir? Bunlar hakkında doküman bulamıyorum.
skyline75489

4
Daha az dağınık, ancak kullanımdan kaldırıldı.
Camille Goudeseune


7

Kolaylığın tüm aritmetik operatörleri için bir işlev olarak tanımlanabilecek başka bir taşınabilir POSIXuyumlu yol .bash.bashrc

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

ve sadece komut satırında

addNumbers 1 2 3 4 5 100
115

Fikir, genişlemeden sonra sözcük bölme ve satırları kelimelere bölme için kullanılan özel bir değişken olan Girdi-Alan-Ayırıcı (IFS)bash kullanmaktır. İşlev, toplam işleci olarak sözcük bölme karakteri kullanmak için değeri yerel olarak değiştirir+ .

Unutmayın IFSlokal olarak değiştirilir ve yok DEĞİL varsayılan tarihinde yürürlüğe girecek IFSfonksiyon kapsamı dışında davranış. Sayfadan bir alıntı man bash,

Kabuk, IFS'nin her karakterine bir sınırlayıcı olarak davranır ve diğer genişletmelerin sonuçlarını bu karakterler üzerindeki kelimelere böler. IFS ayarlanmamışsa veya değeri tam olarak varsayılansa, önceki genişletmelerin sonuçlarının varsayılan,, ve başında ve sonunda yok sayılır ve başında veya sonunda olmayan herhangi bir IFS karakteri dizisi sınırlandırılır kelimeler.

"$(( $* ))"Bölme olmak geçirilen ifade listesini gösterir +kullanarak çıkış ve daha sonra toplam değeri olan printfbir işlev. İşlev, diğer aritmetik işlemler için kapsam eklemek üzere genişletilebilir.


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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.