web-dev-qa-db-ja.com

Bashスクリプトに数字を追加する方法

この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
470
Nick

整数の場合

  • 算術展開を使用します$((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


よくある落とし穴

  • 変数を設定するとき、=の両側に空白を入れることはできません。そうしないと、シェルが最初のWordを実行するアプリケーションの名前として解釈するように強制します(例:num=またはnum

    num= 1num =2

  • bcexprはそれぞれの数と演算子を別々の引数として扱うので、空白が重要です。 3++4のような引数を処理することはできません。

    num=`expr $num1+ $num2`

826
Karoly Horvath

$(( ))算術展開を使用してください。

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

詳細については http://tldp.org/LDP/abs/html/arithexp.html を参照してください。

85
Steve Prentice

やり方は千通りあります。これはdcを使ったものです:

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

しかし、それがあなたには強すぎる(あるいは移植性の問題)なら、あなたは言うことができます

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は浮動小数点数をネイティブにサポートしません。浮動小数点数を合計する必要がある場合は、外部ツール(bcdcなど)を使用する必要があります。

この場合、解決策は

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

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

25
Sorpigal

Bashで、

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

Bashは整数算術しか扱えないので、あなたの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
21
glenn jackman

私はグーグルに来るように私はいつも構文を忘れる、それから私は私がなじみのあるものを見つけることは決してない。これは私にとって最もクリーンで、私が他の言語で期待していることにもっと忠実です。

i=0
((i++))

echo $i;
16
ssshake

私もこの方法がとても好きです。

count=$[count+1]
14
unixball
 #!/bin/bash
read X
read Y
echo "$(($X+$Y))"
9
Amarjeet Singh

Metabを整数として宣言してから算術評価を使用する必要があります。

declare -i metab num
...
num+=metab
...

詳細については https://www.gnu.org/software/bash/manual/html_node/Shell-Arithmetic.html#Shell-Arithmetic を参照してください。

7
Pavel

便利なすべての算術演算子のために.bashrcの中の関数として定義することができるPOSIXで行う別の移植性のあるbash準拠の方法。

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

そして単にコマンドラインで以下のように呼び出します。

addNumbers 1 2 3 4 5 100
115

アイデアは、 入力フィールド区切り文字(IFS) を使用することです。これは、展開後の単語分割に使用されるbash内の特殊変数と、行を単語に分割するためのものです。この関数は、値をローカルに変更して、和演算子+として単語分割文字を使用します。

IFSはローカルに変更され、NOTは関数の範囲外のデフォルトのIFSの動作に影響します。 man bashページからの抜粋

シェルはIFSの各文字を区切り文字として扱い、他の展開の結果をこれらの文字の単語に分割します。 IFSが設定されていない場合、またはその値がデフォルト値の場合は、前の展開の結果の先頭と末尾の、、、とのシーケンスは無視され、先頭または末尾以外のIFS文字のシーケンスは区切り文字として機能します。言葉.

"$(( $* ))"+で分割されるために渡された引数のリストを表し、後で合計値はprintf関数を使って出力されます。他の算術演算にも範囲を追加するように関数を拡張することができます。

6
Inian
#!/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
1