シェルスクリプトBash入門

気分転換にシェルスクリプトを書いてみる。
今回使うシェルは

```vim
$ echo $SHELL
/bin/bash
```

#1.定番の"Hello world!"
まずは作業フォルダーに移動します。
そのあとVimを使ってスクリプトファイルを作ります。

```Bash:hello.sh
#!/bin/bash

echo "Hello World!"
exit 0
```

実行しようと「./hello.sh」とコマンド打つと
`-bash: ./hello.sh: Permission denied`
とパーミッションつまり権限がないと言われる。
`ls -la hello.sh`でみてみると
`-rw-r--r--  1 ebisennet  staff  30 12  4 21:32 hello.sh`
まあ実行権限はないですね。
`chmod u+x hello.sh`
で実行権限を与えます。確認すると
-rwxr--r--  1 ebisennet  staff  30 12  4 21:32 hello.sh
実行できますね。

```
$ ./hello.sh
Hello World!
```
できましたね。

ちなみに`exit 0`正常終了の意味
コメントは行頭#でその行はコメントできる
セミコロンを使うことで１行にまとめることができる。

```vim:hello.sh
#!/bin/bash

# コメント
echo "hello world!";exit 0
```

#2.変数

```vim:hello.sh
#!/bin/bash↲
↲
# 変数　=の両端にスペースを入れない↲
↲
# 文字列↲
# 'は変数展開されないことに注意↲
s="Hello"↲
↲
echo $s↲
echo "$s"↲
echo "${s}" #こちらを使った方が他の環境でも実行されやすい↲
echo $s$s↲
echo "$s $s"↲
echo "${s} ${s}"↲
echo '$s'↲
```

結果

```vim.bash
$ ./hello.sh
Hello
Hello
Hello
HelloHello
Hello Hello
Hello Hello
$s
```

数値

```vim:hello.sh
#!/bin/bash↲
↲
# 変数　=の両端にスペースを入れない↲
↲
# 数値↲
↲
x=10↲
echo $x↲
echo $x+2↲
```

結果

```
$ ./hello.sh
10
10+2
```

計算されていないことに注意してください
計算するには

```
echo `expr $x + 2`
```

としなければならない。スペースを一つ一つ空けなければならない。

```
$ ./hello.sh
10
10+2
12
```

四則演算、優先計算、readonly

```
#!/bin/bash↲
↲
# 変数　=の両端にスペースを入れない↲
# 値を変更させないようにするには readonly 変数名=値↲
# 数値↲
↲
x=10↲
echo `expr $x + 2`↲
echo `expr $x - 2`↲
echo `expr $x \* 2`↲
echo `expr $x / 2`↲
↲
↲
echo `expr \( $x + 5 \) \* 2`↲
echo `expr $x / 2`↲
↲
readonly y=10↲
y=20↲
```

実行結果

```
$ ./hello.sh
12
8
20
5
30
5
./hello.sh: line 18: y: readonly variable
```

#配列

```
#!/bin/bash↲
↲
# 配列↲
↲
a=(2 4 6)↲
↲
echo $a↲
echo "---------------"↲
echo ${a[0]}↲
echo ${a[1]}↲
echo ${a[2]}↲
echo "---------------"↲
# @は全ての要素 #は要素数↲
echo ${a[@]}↲
echo ${#a[@]}↲
```

実行結果

```
$ ./hello.sh
2
---------------
2
4
6
---------------
2 4 6
3
```

注意 $a[1]は`2[1]`と表示される

###配列の要素変更

```
#!/bin/bash↲
↲
# 配列↲
↲
a=(2 4 6)↲
↲
# 要素の変更↲
a[2]=10↲
echo ${a[@]}↲
echo "---------------"↲
# 要素の追加↲
a+=(20 30)↲
echo ${a[@]}↲
echo "---------------"↲
# 応用 `でくくったところは実行結果を返すもの↲
d=(`date`)↲
echo ${d[3]}
```

実行結果

```
$ ./hello.sh
2 4 10
---------------
2 4 10 20 30
---------------
14時50分44秒
$ date
2016年 3月15日 火曜日 14時50分50秒 JST
```

#条件分岐

```
#!/bin/bash↲
↲
# 条件式↲
# 正常終了(0)↲
↲
# 数値の評価↲
↲
# 1=2ではないので1が出力される。$?は正常終了かそれ以外かがわかる。↲
test 1 -eq 2; echo $?↲
test 1 -eq 1; echo $?↲
echo "----------------"↲
# -ne <> or !=↲
test 1 -ne 2; echo $?↲
# >↲
test 1 -gt 2; echo $?↲
# >=↲
test 1 -ge 2; echo $?↲
# <↲
test 1 -lt 2; echo $?↲
# <=↲
test 1 -le 2; echo $?↲
```

実行結果

```
$ ./hello.sh
1
0
----------------
0
1
1
0
0
```

文字列、ファイルに対しての条件式

```
#!/bin/bash↲
↲
# 条件式↲
# 正常終了(0)↲
↲
#文字列の評価↲
↲
# =↲
# !=↲
↲
# ファイル↲
# -nt (newer than)↲
# -ot (older than)↲
# -e↲
# -d↲
test -e hello.sh; echo $?↲
↲
# 論理演算子↲
# -a (and)↲
# -o (or)↲
# ! (否定)↲
test 1 -eq 1 -a 2 -eq 2; echo $?↲
```

実行結果

```
$ ./hello.sh
0
0
```

#IF文

```
#!/bin/bash

# if文

x=70
if test $x -gt 60
then
  echo "ok!"
fi
# 上と同じ処理[]はテストの命令となっているためスペースが必要
if [ $x -gt 60 ]; then
  echo "ok!"
fi
# 複数条件
echo "-----------------"
y=40
if [ $y -gt 60 ]; then
  echo "ok!"
else
  echo "soso..."
fi

if [ $y -gt 60 ]; then
  echo "ok!"
elif [ $y -gt 40 ]; then
  echo "soso..."
else
  echo "ng..."
fi
```

実行結果

```
$ ./hello.sh
ok!
ok!
-----------------
soso...
ng...
```

#case文

```
#!/bin/bash↲
↲
# case文↲
↲
signal="red"↲
case $signal in↲
  "red")↲
    echo "stop!"↲
    ;;↲
  "yellow")↲
    echo "caution!"↲
    ;;↲
  "green")↲
    echo "go!"↲
    ;;↲
  *)↲
    echo "..."↲
    ;;↲
esac↲
```

実行結果

```
$ ./hello.sh
stop!
```

#while文

```
#!/bin/bash

# while

i=0
while [ $i -lt 10 ]
do
  i=`expr $i + 1 `
  echo ${i}
done

echo "------------"

# 無限ループ :は正常終了コマンドで常にtureになるのでループする。
j=0
while :
do
  j=`expr $j + 1 `

  if [ $j -eq 3 ]; then
# $i=3の時処理を飛ばす
    continue
  fi 

  if [ $j -gt 10 ]; then
# $i>10の時はループを抜け出し終了
    break
  fi

  echo ${j}
done
```

実行結果

```
$ ./hello.sh
1
2
3
4
5
6
7
8
9
10
------------
1
2
4
5
6
7
8
9
10
```

#for文

```
#!/bin/bash↲
↲
# for文↲
↲
for i in 1 2 3 4 5↲
do↲
  echo ${i}↲
done↲
↲
echo "-------------"↲
↲
# 配列バージョン $iは上でも使われているので注意(普通は区別します。)↲
↲
a=(1 2 3 4 5)↲
↲
for i in ${a[@]}↲
do↲
  echo ${i}↲
done↲

# 省略型↲
↲
for i in `seq 1 5`↲
do↲
  echo ${i}↲
done↲
```

実行結果

```
$ ./hello.sh
1
2
3
4
5
-------------
1
2
3
4
5
-------------
1
2
3
4
5
```

ちなみに、continue,breakも使用可能

#コマンドに引数を渡す

```
#!/bin/bash↲
↲
echo $0 #自分自身参照↲
echo $1 #第一引数↲
echo $2 #第二引数↲
# echo ${10} #第10引数(10以降はカッコをつける)↲
↲
echo $@ #引数全て↲
echo $# #引数の個数↲
```

実行結果

```
$ ./hello.sh a b
./hello.sh
a
b
a b
2
```


#ユーザーからの入力の受付

```
#!/bin/bash↲
↲
# read↲
↲
while :↲
do↲
  # 入力を受け取る↲
  read key↲
  echo "you pressed ${key}"↲
  if [ ${key} = "end" ]; then↲
    break↲
  fi↲
done↲
↲
# 選択肢から選ばせる↲
select option in CODE DIE↲
do↲
  echo "you pressed ${option}"↲
  break↲
done↲
```

実行結果

```
$ ./hello.sh
ok
you pressed ok
end
you pressed end
1) CODE
2) DIE
#? 2
you pressed DIE
```

#ファイルから入力

データを作成する

```vim:data.txt
hello↲
hoge↲
nyoro
```

```vim:hello.sh
#!/bin/bash↲
↲
i=1↲
while read line #受け取ったデータを１行ずつ処理↲
do↲
  echo "${i}: ${line} "↲
  i=`expr $i + 1`↲
done <$1 #第一引数の指定↲
```

実行結果

```
$ ./hello.sh date.txt
1: hello
2: hoge
3: nyoro
```

#関数

```
#!/bin/bash↲
↲
# 関数↲
function hello() {↲
  echo "hello"↲
}↲
hello↲
#functionは省略可能である。 hello() {}↲
ok() {↲
  echo "ok"-↲
}↲
ok↲
#引数を使う↲
hello2() {↲
  echo "hello2 $1 and $2"↲
}↲
hello2 Mike Tom↲
```

実行結果

```
$ ./hello.sh
hello
ok
hello2 Mike and Tom
```

次

```
#!/bin/bash↲
↲
# 関数 ローカル変数、グローバル変数↲
function hello() {↲
  echo "hello"↲
  i=5↲
  echo ${i}↲
}↲
↲
hello↲
echo "-------------"↲
echo ${i}↲
```

実行結果

```
$ ./hello.sh
hello
5
-------------
5
```

次

```
#!/bin/bash↲
↲
# 関数 ローカル変数、グローバル変数↲
function hello() {↲
  echo "hello"↲
  i=5↲
  local j=10↲
  echo "${i} ${j}"↲
}↲
↲
hello↲
echo "-------------"↲
echo ${i}↲
echo ${j}↲
```

実行結果

```
$ ./hello.sh
hello
5 10
-------------
5

```

local変数を参照した場合空行になっています。