Bashスクリプトに数値を追加するにはどうすればよいですか?


566

このBashスクリプトがあり、16行目に問題がありました。15行目の以前の結果を取得して、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

2
次の答えでもゼロ値を出力すると思います。"subside num"の最終的な値を "outside num"にするためのトリック(例えば、プロセス置換)があります。
Scott Chu

回答:


976

整数の場合

  • 算術展開を使用します。$((EXPR))

    num=$((num1 + num2))
    num=$(($num1 + $num2))       # Also works
    num=$((num1 + 2 + 3))        # ...
    num=$[num1+num2]             # Old, deprecated arithmetic expression syntax
  • 外部exprユーティリティを使用します。これは本当に古いシステムにのみ必要であることに注意してください。

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

浮動小数点の場合

Bashはこれを直接サポートしていませんが、使用できる外部ツールがいくつかあります。

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

科学表記法(たとえば、2.5e+2)を使用することもできます。


一般的な落とし穴

  • 変数を設定する場合、のいずれかの側に空白を含めることはできません=。そうしないと、シェルは最初の単語を実行するアプリケーションの名前として解釈します(例:num=またはnum)。

    num= 1 num =2

  • bcまたexpr、各数値と演算子は個別の引数として想定されるため、空白が重要です。のような引数を処理することはできません3+ +4

    num=`expr $num1+ $num2`


1
第二は、仕事をしない非数値引数を..:最初の答えでは、それは私がexprを出力します
ニック・

1
@ニック:変数に名前が付けられnum1num2存在し、整数値があるときに、これを試しましたか?
sorpigal

1
それらは存在しますが、1つの変数はdoubleです。これは問題ですか?
Nick

2
ええ、それは問題です:)注:$((..))算術評価はbashで実行されます。exprは別のプロセスとして実行されるため、かなり遅くなります。アリテム評価がサポートされていないシステム(sh!= bash)で後者を使用する
Karoly Horvath

4
以来$((…))POSIXによって標準化され、そのますます稀なるべきexpr必要があります。
chepner 2013年


30

それを行う方法は千通りあります。以下はdc、使用するものです(無制限の精度演算をサポートするリバースポリッシュデスク計算機)。

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

しかし、それがあなたにとってあまりにもbash-yである場合(または移植性の問題)、次のように言うことができます。

echo $num1 $num2 + p | dc

しかし、おそらくあなたはRPNがおかしくて変だと思っている人の1人でしょう。心配しないで!bcあなたのためにここにあります:

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

そうは言っても、スクリプトに関係のないいくつかの改善点があります。

#!/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 FAQ 022で説明されているように、Bashは浮動小数点数をネイティブでサポートしていません。浮動小数点数を合計する必要がある場合は、外部ツール(bcまたはなどdc)を使用する必要があります。

この場合の解決策は

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

浮動小数点数の累積をに追加しnumます。


1
@Sorpigal Thankssssたくさん..私はあなたに何か他のものを尋ねることができます..numではなくnum / 10の最後にどのように印刷できますか?
Nick

23

bashでは

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

bashは整数演算しか処理できないので、awkコマンドが小数部を返す場合は、再設計する必要があります。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

20

私はいつも構文を忘れているのでグーグルに行きますが、私が慣れている構文を見つけることはできません:P。これは私にとって最もクリーンで、他の言語で期待するものにより忠実です。

i=0
((i++))

echo $i;


15

私はこの方法も本当に気に入っています。

count=$[count+1]

1
ところで、なぜこれが機能しているのですか?これをどう呼ぶか?これらに関するドキュメントが見つかりません。
skyline75489

4
よりすっきりとしていますが、非推奨です。
Camille Goudeseune


7

で行うもう1つの移植可能なPOSIX準拠方法bash。これは.bashrc、便利なすべての算術演算子の関数として定義できます。

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

そして、それをコマンドラインで次のように呼び出すだけです:

addNumbers 1 2 3 4 5 100
115

アイデアは、Input-Field-Separator(IFS)bash使用することです。これは、展開後の単語分割と、行を単語に分割するために使用される特別な変数です。関数は、値をローカルで変更して、合計演算子として単語分割文字を使用します+

覚えておいてくださいIFSローカルに変更されず、NOT、デフォルトで有効になるIFS機能の範囲外で動作。man bashページからの抜粋、

シェルはIFSの各文字を区切り文字として扱い、他の拡張の結果をこれらの文字の単語に分割します。IFSが設定されていない場合、またはその値がデフォルトのである場合、以前の展開の結果の最初と最後の、、およびのシーケンスは無視され、最初または最後にないIFS文字のシーケンスは区切り文字として機能します。言葉。

"$(( $* ))"引数のリストにより分割する渡さ表す+合計値を用いて出力され、以降のprintf機能を。関数を拡張して、他の算術演算のスコープを追加することもできます。


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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.