Shellの基本を学ぶ（６）Variables 2

# Integer Variables
基本的に、Shell Script では、変数は文字だが、Integer として使う方法がある。

`declare -i variable` を指定すると、その変数をIntegerにすることができる。ちなみに、文字を代入してもエラーは起こらないが、０という扱いになる。

調べてみると、`declare`は`typeset`のシノニムで、変数のプロパティを変更するもの。次のものがある。

* `-r` Readonly  
* `-i` Integer
* `-a` array
* `-f` function
* `-x` export　

* [9.2. Typing variables: declare or typeset](http://tldp.org/LDP/abs/html/declareref.html)

```bash
$ p="3+2"
$ echo $p
3+2
$ declare -i p
$ p="3+2"
$ echo $p
5
$ p="abc"
$ echo $p
0
```

# Arithmetic Expression

C言語のような構文が使える。

いくつかの方法がある。

## let 

```bash
let n=100/4
```

## (( .. )) 
let と同じだが、著者は、let の方が好みらしい。スペースが使えるとか（よくわかってない）

```bash
((++x))
((p=x/100))
(( p= $(ls | wc -l) * 10)) # 空白あってもなくても同じだった。
```

上記のスペースのいちが曖昧。あとで確認

## $(( .. ))
これは、Substitution なので、計算結果が置き換えられる。

```bash
p=$(( x / 100 ))
```

## integer で定義された変数を使う

declare -i で定義された変数を使う

```bash
num="30 % 8"
```

## サンプル

```bash
 declare -i x
$ x=100/2
$ echo $x
50
$ $((++x)) # Substitution なので、51に置き換えられて解釈される
-bash: 51: command not found
$ ((++x))
$ echo $x
52
$ x=$((x+1))
$ echo $x
53
$ (( p= $(ls | wc -l) * 10)) # スペースを詰めても同じ結果だった。
$ echo $p
230
```

## Tips

* クオートは必要ない。あってもいいけど
* ((..))はif, while で使えるけど、0がfalseになるので注意（コマンド実行と逆)
* 0始まりの数字は、８進数として計算される
* For ループの ((..; ..; ..)) 自体は Arithmetic Expression ではないが、内部は Arithmetic Expression

* [Arithmetic Expression](https://wiki.bash-hackers.org/syntax/expansion/arith?s%255B%255D=arithmetic)

## サンプル

サンプルが面白かったので写経。ポイントとしては、Integer Variable と`$((..))` `((..))`構文で計算しているところ。ちなみに、`$RANDOM`はIntegerの範囲のランダムな数値を返すので、若干偏りがあるような気がするが、余りを求めることで、特定の範囲のランダムな数字を取得している。

```bash
#!/bin/bash

# Get a random number 0 < target < 100
declare -ir target=$(( ($RANDOM % 100)))

declare -i guess=0

until (( guess == target )); do
  read -p "Guess the number: " guess

  # guess should not be 0
  (( guess )) || continue # 渋い

  if (( guess < target )); then
    echo "Greater than that!"
  elif (( guess > target )); then
    echo "Less than that!"
  else
    echo "You've found it!"
  fi
done

exit 0

```

### 実行

```bash
$ ./game
Guess the number: 50
Greater than that!
Guess the number: 75
Less than that!
Guess the number: 62
Greater than that!
Guess the number: 68
Less than that!
Guess the number: 66
Less than that!
Guess the number: 65
Less than that!
Guess the number: 64
```

# export variables

サブプロセスに変数を使えるようにする。呼び元には、残念ながら変数を渡せない。（この書き方では）

```bash
export var="value"
declare -x var="value"
```
さらに、サブプロセスには、アトリビュートは渡らない。アトリビュートは、例えば、`declare -xr` のxrなど。

## サンプル
ポイントとしては、親で定義して、`export`もしくは、`declare -x` で定義したものはサブプロセスでも使えるが、そのアトリビュートは渡らないので、親でreadOnly指定をしても子で上書きできる。子で、export しても、親の方にはその変数は渡らない。ちなみに、サブプロセスからペアレントに環境変数を渡したかったらファイル経由で行くしかないとのこと。`PowerShell`はスコープがあるから可能だった。


_parent_

```bash
#!/bin/bash

declare -xr parentVariable="Parent worte this"
declare -r  parentOnlyVariable="Parent only variable"
echo "Parent: ParentVariable: ${parentVariable}"
echo "Parent: ParentOnlyVariable: ${parentOnlyVariable}"
./child
echo "Parent: ParentVariable: ${parentVariable}"
echo "Parent: ParentOnlyVariable: ${parentOnlyVariable}"
echo "Parent: ChildVariable: ${childVariable}"

```

_child_

```bash
#!/bin/bash

echo "Child: ParentVariable: ${parentVariable}"
echo "Child: ParentOnlyVariable: ${parentOnlyVariable}"
declare -x childVariable="Child only variable"
parentVariable="override by child"
echo "Child: ParentVariable: ${parentVariable}"
echo "Child: ParentOnlyVariable: ${parentOnlyVariable}"
echo "Child : ChildVariable: ${childVariable}"
```

### 実行

```bash
$ ./parent
Parent: ParentVariable: Parent worte this
Parent: ParentOnlyVariable: Parent only variable
Child: ParentVariable: Parent worte this
Child: ParentOnlyVariable:
Child: ParentVariable: override by child
Child: ParentOnlyVariable:
Child : ChildVariable: Child only variable
Parent: ParentVariable: Parent worte this
Parent: ParentOnlyVariable: Parent only variable
Parent: ChildVariable:
```
# Array

* x[0]="some"
* x[1]="word"
* ${x[0]} # return some
* ${x[1]} # return word

`${x[@]} や ${x[*]}` は全ての値を取得する。(クオートは、`$*`や`$@`と同じように動く

## 定義

`declare -a var` もしくは、上記のようにindex付きの変数にアサインする。

```bash
ar=(1 2 3 a b c)
```
と行った記述も可能。

## カウント

* ${#array[@]} # 要素数を返す
* ${!array[@]} # インデックスのみを返す

Array は export 出来ないらしい。bash 4 は、アソシエーティブArray を使えるらしい。index ではなく、名前を指定できる。(Map?) `declare -A array` で良いらしい。

* [arrays](https://wiki.bash-hackers.org/syntax/arrays?s%255B%255D=arrays)


```bash
$ ar=(hello people this is array)
$ declare -p ar
declare -a ar='([0]="hello" [1]="people" [2]="this" [3]="is" [4]="array")'
$ echo ${ar[3]}
is
$ ar[12]="again"
$ declare -p ar
declare -a ar='([0]="hello" [1]="people" [2]="this" [3]="is" [4]="array" [12]="again")'
$ echo ${$ar[@]}
-bash: ${$ar[@]}: bad substitution
$ echo ${#ar[@]}
6
$ echo ${!ar[@]}
0 1 2 3 4 12
```

ちなみに、`-p` は全ての変数の値を表示するためのオプション.

* [10.1.2. Using the declare built-in](https://linux.die.net/Bash-Beginners-Guide/sect_10_01.html)