2016/07/15

Bシェルのシェルスクリプトの中で演算を行う

BashDash,ZshなどのBシェルを用いたシェルスクリプトの中で演算処理が必要な場合の書き方についてを扱う。

  1. 演算子
  2. 計算式の記述
    1. シェル内部の記法
    2. exprコマンド
    3. その他の外部コマンドで計算を行う
  3. 計算結果を変数に代入する
  4. スクリプト例

演算子

演算子結果
A + BAにBを足した値
A - BAからBを引いた値
A * BAにBを掛けた値
A / BAをBで割った商
A % BAをBで割った余り

AとBは基本的に整数である必要がある。

計算式の記述

シェル内部の記法

“$((” と “))” の間に計算式を入力する。Zshでは割り算で小数を扱うことができたり、 “**” 演算子で累乗や累乗根が計算できたりする。

(3 + 4 の足し算)
$ echo "3 + 4 = $((3 + 4))"
3 + 4 = 7

(10 − 15 の引き算)
$ echo "10 - 15 = $((10 - 15))"
10 - 15 = -5

(2 × 9 の掛け算)
$ echo "2 x 9 = $((2 * 9))"
2 x 9 = 18

(77 ÷ 6 の割り算の商と余り)
$ echo "77 = $((77 / 6)) x 6 + $((77 % 6))"
77 = 12 x 6 + 5

(Zshで小数を扱う割り算を実行)
Zsh$ echo "1 / 100.0 = $((1 / 100.0))"
1 / 100.0 = 0.01

(Zshで2の6乗を計算)
Zsh$ echo "2 ** 6 = $((2 ** 6))"
2 ** 6 = 64

(Zshで2の12乗根を計算)
Zsh$ echo "2 ** (1 / 12.0) = $((2 ** (1 / 12.0)))"
2 ** (1 / 12.0) = 1.0594630943592953

exprコマンド

外部コマンドのexprも上と同様に動作する。

(4 + 1 の足し算)
$ echo "4 + 1 = $(expr 4 + 1)"
4 + 1 = 5

(23 − 12 の引き算)
$ echo "23 - 12 = $(expr 23 - 12)"
23 - 12 = 11

(3 × 2 の掛け算)
$ echo "3 x 2 = $(expr 3 * 2)"
3 x 2 = 6

(123 ÷ 33 の割り算の商と余り)
$ echo "123 = $(expr 123 / 33) x 33 + $(expr 123 % 33)"
123 = 3 x 33 + 24

exprは他の判定処理などの幾つかの用途でも使えるが、ここでは扱わない。

その他の外部コマンドで計算を行う

expr以外にも、Perlなどの各種インタプリタで計算処理を行ってその結果を出力するようなコードを渡す方法や、bcコマンドに計算式を渡して結果を得る方法もある。これにより、数学関数を用いた計算や複雑な計算も可能となる。

(Perlを用いた例)
$ echo "2 ** 10 = $(echo "print 2 ** 10" | perl)"
2 ** 10 = 1024

(bcを用いた例・小数点以下2桁指定)
$ echo "1 / 100 = $(echo "scale=2; 1 / 100" | bc)"
1 / 100 = .01

bcは任意精度の数値が(内部的にも10進数として)扱えるのが強みだが、独自の1つの言語でもあるため、慣れるまでに使いにくさを感じることがありうる。

計算結果を変数に代入する

計算結果を変数に代入するには “[変数名]=” の後ろに計算結果が入るようにする。

  • [変数名]=$(( [計算式] ))
  • [変数名]=$(expr [計算式])
  • [変数名]=$(echo "[計算式や表示命令など]" | [計算コマンド])
  • [変数名]=$([計算コマンド] [オプション] "[計算式や表示命令など]")

スクリプト例

[任意]ファイル名:sum.sh
#! /bin/sh

# 1から引数の値までの合計を計算する
# 桁数が多くなると時間がかかるので注意

if test ${#} -eq 0
then
  echo "使い方: ${0} [最後の値 (>= 1)]" >&2
  exit 1
fi

LAST=${1}
if test ${LAST} -ge 1 2> /dev/null
then
  # 合計値を入れる変数TOTALの初期値を0とする
  TOTAL=0

  # カウンタ変数Iの初期値を1とする
  I=1
  # Iが引数値以下のときにループが続き、ループ内でTOTALにその値を加算する
  while test ${I} -le ${LAST}
  do
    TOTAL=$((${TOTAL} + ${I}))

    I=$((${I} + 1))
  done

  # ループで計算した合計を表示
  echo "1 から ${LAST} までの合計は ${TOTAL}"
  # "n (n + 1) / 2" の式に当てはめて計算した結果も表示
  echo "${LAST} × $((${LAST} + 1)) ÷ 2 は $((${LAST} * $((${LAST} + 1)) / 2))"
  exit 0
else
  echo "値が不正です" >&2
  echo "使い方: ${0} [最後の値 (>= 1)]" >&2
  exit 1
fi
使用例
$ /path/to/sum.sh 10
1 から 10 までの合計は 55
10 × 11 ÷ 2 は 55

$ /path/to/sum.sh 50
1 から 50 までの合計は 1275
50 × 51 ÷ 2 は 1275

$ /path/to/sum.sh 77777
1 から 77777 までの合計は 3024669753
77777 × 77778 ÷ 2 は 3024669753
使用したバージョン:
  • Dash 0.5.8
  • Bash 4.3
  • Zsh 5.1.1
  • Coreutils 8.25
  • Perl 5.22.1
  • GNU bc 1.06.95