シェルスクリプトの基礎知識まとめ



# 基本ルール

## 決まり文句

１行目に利用するシェルを書く

```sh:hello.sh
#!/bin/bash
```
# 実行

## 実行権限を設定してから実行

```
$ chmod +x hello.sh
$ ./hello.sh
```

# 変数

### 正しい書き方

```sh:hello.sh
s="hello"

# こういう書き方ができる
echo $s #hello
echo "$s" #hello
echo "${s}" #hello

# 文字列の連結はくっつけるだけ
echo $s$s # hellohello
echo "$s $s" # hello hello
```
### 間違った書き方
以下、まねしないように。

```sh:hello.sh
# =の前後にスペースを入れてはいけない。
s = "hello"
# 変数の中身ではなく文字列として表示されてしまう
echo '$s'

```

## 四則演算

### ポイント
- 計算したい時は`(バッククォート)を使う
- 数値として展開したい変数の前にexprを使う。（この時計算する四則演算記号の前後にスペースを入れる）
- 掛け算やカッコを使う場合は \\* のように、記号の前にバックスラッシュが必要（エスケープ）
- readonly とすると変数の上書きができなくなる

```sh:hello.sh
x=10
echo $x # 10
echo $x+2 # 10+2
echo `expr $x + 2` # 12
echo `expr \($x + 5\) \* 2` # 30 

readonly y=20
y=25 # y: readonly variableというエラーが出る
```
# 配列
## 扱い方
### ポイント
- 添字を指定して中身を取り出すには波括弧を使う
- $aで最初の要素が表示される
- ${a[@]}で全ての要素が表示される
- ${#a[@]}で要素数が表示される


```sh:hello.sh
a=(2 4 6)
echo $a # 2
echo ${a[0]} # 2
echo ${a[1]} # 4
echo ${a[@]} # 2 4 6
echo ${#a[@]} # 3

# 波括弧を忘れた場合、最初の要素と文字列を連結した文字列になる
echo $a[1] # 2[1]

```

## 値の代入、要素の追加

### ポイント

- 代入、追加時に波括弧は要らない
- \`date`は日付や曜日を要素とした配列になっている。

```sh:hello.sh
a=(2 4 6)
a[2]=10 
echo ${a[@]} # 2 4 10

a+=(20 30)
echo ${a[@]} # 2 4 10 20 30

d=(`date`)
echo $d # 2014年 11月 12日 水曜日 11時09分30秒 JST
echo ${d[3]} # 水曜日

```


# 条件式

## 条件式の評価
### ポイント
- 正常終了は0が返ってくる
- testコマンドで条件式を評価できる（ちなみにtestは[]で置き換え可能）
- $?で、直前に終了した命令が正常終了したかどうかを評価する

#### 比較演算子
- -eq ： equal
- -ne ： not equal
- -gt ： greater than (◯◯より大きい)
- -ge ： greater than or equal (◯◯以上)
- -lt ： less than (◯◯より小さい)
- -le ： less than or equal (◯◯以下)

```sh:hello.sh

test 1 -eq 2; echo $? # 1 ←正常でない
test 1 -eq 1; echo $? # 0 ←正常終了
```

### 文字列とファイル
#### 文字列の比較演算子
- = ： equal
- != ： not equal

#### ファイルの比較演算子
- -nt ： newer than
- -ot ： older than
- -e ： exist (存在しているかどうか)
- -d ： directory (ディレクトリかどうか)

### 論理演算子
- -a ： and
- -o ： or
- ! ： is not

```sh:hello.sh

# ファイルが存在するかどうか
test -e hello.sh; echo $? # 0

# 1 = 1 && 2 == 2 
test 1 -eq 1 -a 2 -eq 2; echo $? # 0

```

# 条件分岐

## if文
- ifのあとに条件式を書く
- 条件に合致していればthenからfiまで実行

```sh:hello.sh

x=20
if [ $x -gt 60 ]
 then
  echo "ok!"
elif [ $x -gt 40 ]
 then
  echo "soso..."
else
  echo "ng...."
fi

# ng....
```


## case文
- caseの値に合致したときに処理は)から;;まで
- 何にも当てはまらない時の条件は*)で指定する

```sh:hello.sh

signal="red"
case $signal in
 "red")
  echo "stop!"
  ;;
 "yellow")
  echo "caution!"
  ;;
 "green")
  echo "go!"
  ;;
 *)
  echo "..."
  ;;
esac
# stop!
```
# ループ処理
## while文

- 条件式の間だけdoとdoneの間の処理を行う

### 基本

```sh:hello.sh
i=0
while [ $i -lt 10 ]
do
	i=`expr $i + 1`
	echo $i
done

```

### 途中で抜けたりしたい時

```sh:hello.sh
# $iが3の時にはなにもしない
# $iが10より大きくなったらループ終了
i=0
while : # :を使うと常に0(正常終了)を返すので、無限ループになる
do
	i=`expr $i + 1`
	if [ $i -eq 3 ]; then
		continue
	fi
	if [ $i -gt 10 ]; then
		break
	fi	
	echo $i
done
```

## for文

inに続くスペース区切りの値を入れていきdoとdoneの間の処理を実行

```sh:hello.sh
for i in 1 2 3 4 5
do
	echo $i
done

```


### 配列を使いたい時

```sh:hello.sh
a=(1 2 3 4 5)
for i in ${a[@]}
do
	echo $i
done
```


# コマンド引数の使い方

```sh:hello.sh
echo $0 # ファイル名
echo $1 # 1番目の引数
echo $2 # 2番めの引数
echo $@ # 全ての引数
echo $# # 引数の数
```

# ユーザーからの入力を受け付る
readコマンドを使うことで受け取った値を変数に代入できる。以下はkeyという変数にユーザーの入力した値を入れて処理している。

```sh:hello.sh
while : 
do
	read key
	echo "you pressed $key"
	if [ $key = "end" ]; then
		break
	fi
done

```
## 選択肢で選ばせる
- select というコマンドを使う



```sh:hello.sh
select option in CODE DIE
do
	echo "you pressed $option"
	break;
done
```

選択肢が表示され、ユーザーは数字で選べる。

```
1) CODE
2) DIE
#? 1
you pressed CODE
```

# ファイルから入力する

以下は引数に指定したファイルを読み込み、行番号を表示する処理

読み込むデータ。

```txt:data.txt
a
aa
aaa
```
実行ファイル

```sh:hello.sh
i=1
while read line # 変数lineに1行ずつ格納される
do
	echo "$i: $line"
	i=`expr $i + 1`
done <$1 # ここで読み込むファイルを指定（引数）
```
実行

```
$ ./hello.sh data.txt
```

# 関数

- 関数内で作った変数は関数外でも使用できる。ローカル変数にしたい場合は local i=5 みたいにlocalを使う
- functionは省略可能

```sh:hello.sh
# functionは省略可能
hello() {
	echo "hello $1 and $2" # hello Mike Tom
	i=5
	echo $i
}
hello Mike Tom
```