今更ながら、シェルスクリプトを一から勉強してみた

# はじめに
　とある作業をcronに設定して自動化したかったので、その時勉強したシェルスクリプトについてのまとめです。今どきはPythonでコマンド実行できてしまいますが、シェルスクリプトならLinux環境さえあればどこでも実行できるので、こちらを選択しました。
　慣れるまで少しだけ時間がかかりましたが、やってること自体は単純なのでコツさえつかめば誰でも書けるようになると思います。

# そもそもシェルスクリプトとは?
> POSIXおよびIEEE Std 1003.1-2008で定義されたシェルコマンド言語を用いるスクリプトである。通常、オペレーティングシステムのシェルまたはコマンドラインインタプリタ向けに書かれる。狭義では、Unixシェルで用いられるスクリプト言語を指す。
wikipedia 引用

　簡単に言うと、**複数のコマンドを書き留めておいて、それらを上から実行してくれるファイル**のこと。書き留めたコマンドをまとめて実行できるようになるので、cronなど定期的に実行するときに便利。拡張子は.sh。

# 開発環境
　コーディングするうえで、環境はとっても大事

- エディタ
    - Visual Studio Code
- 拡張機能(意外と大切)
    - ShellCheck
        - 文法ミスやタイポを指摘してくれる
        - 場合によっては1クリックで修正できるので便利
    - Error Lends
        - 波線の中身をソースコードの右側に表示してくれる
        - わざわざマウスカーソルを合わせなくていいので便利
    - shell-format
        - 保存したとき、スクリプトのフォーマットを整えてくれる
        - 人によっては好き嫌い分かれるかも?

# 書き方
## シバン 
　シバン(shebang)はインタプリタを指定するために書きく。「シェバン」とか「シェバング」なんて呼ばれることもあり、これを指定しないとインタプリタが指定されないため、動作が不安定になってしまう(かもしれない)。シェルスクリプトでは1行目に以下のように書く。

```shell
#! /bin/bash
```
## コメント
　シェルスクリプトのコメントアウトは「#」で行います。

```shell
#! /bin/bash

# これはコメントです
# 実行されないので処理内容などを書き込みましょう
```

また、「"<< 任意文字列" コード "任意文字列"」で複数行コメントアウトすることもできる。

```shell
#! /bin/bash

<< COMENTOUT
ここもコメントなので実行されません
スクリプトの仕様をトップに書いておく時などに便利です
COMENTOUT
```

~~シバンは「#!」で指定するのに、コメントも「#」とは意地悪ですね~~
## 実行順番
　基本的に上から順に実行される。

```shell
#! /bin/bash

ls -la                        # bashのコマンドは基本なんでも使える
cd /var/www/html/             # パスを指定するタイプのものは絶対パスで指定しましょう
echo 'これが最後に実行されます'
exit 0                        # C言語いうところのreturn システム変数'$?'に0を渡します
``` 
コマンドは基本的になんでも使えます。特に`echo`と`>>`はよく使う。
# 変数
　変数はアルファベットと数字の組み合わせで宣言できます。代入するときは名前だけでよいが、使うときは`$`を付けて呼び出す。
　再書き込みをされたくない場合は`readonly`とすることで再書き込みを防止できる。

```shell
#! /bin/bash

str='変数'        # `=`の前後にスペースを入れてはいけません
readonly NUM=100  # 再代入をしたくない場合はこちら。定数になるので、大文字で宣言すると良いかも
today=`date`      # 出力結果を変数に入れることもできます

echo $str         # 呼び出すときは'$'を付けます
echo $(ls -la)    # 実行結果を呼び出すときは'$(コマンド)'とします
```
### 特殊変数
　もちろん、システムで予約された変数が存在する。

|変数| |
|---|---|
|$#|コマンドライン引数の数|
|\$1 ~ \$9|コマンドライン引数|
|\$0|実行したコマンド|
|\$?|最後に実行したコマンドの終了状態。成功時は0、失敗時はそれ以外の値が入っていることが多い|
|\$$|現在のシェルのプロセス番号|
よく使うのはこのあたり

## if文
　シェルスクリプトでもif文で条件分岐することができる。
`if [ 条件文 ] then <コマンド> elif [ 条件文 ] then <コマンド> else fi`と書く。

```shell
#! /bin/bash

var='Hello'
if [ $var = 'Hello' ];      # 大括弧の内側の端には必ず空白を入れること
then
    echo 'Hello'
fi

if [ ! $var = 'こんにちは']; # 全体を否定するときは左端に'!'を書く
then
    echo 'こんにちは'
else;                       # elseには'then'が不要
    echo 'さただばー'
fi
```
### 比較演算子
シェルスクリプトは数値比較の演算子が少し特殊

|演算子|意味|
|--|--|
|A = B|左右の文字列が一致したときに真|
|A != B|左右の文字列が不一致のときに真|
|A -eq B|数値が一致すれば真|
|A -ne B|数値が不一致ならば真|
|A -ge B|AがB以上なら真|
|A -gt B|AがBより大きれけれ真|
|A -le B|AがB以下なら真|
|A -lt B|AがBより小さければ真|

### ファイルの存在チェック
ファイルが存在するかどうかもif文で行うことができる。
サンプルでは相対パスで指定しているが、__絶対パスで指定した方が絶対良い__

```shell
#! /bin/bash

# 指定された名前のファイルorディレクトリが存在する場合
# if [ -e 'sample' ];

# 指定された名前のディレクトリが存在する場合
# if [ -d 'sample' ];

# 指定された名前のファイルが存在する場合
if [ -f 'sample' ]; 
then
    echo 'sampleが存在します'
    rm sample
fi
```

## 関数
シェルスクリプトでは関数も宣言できる。
`function <任意の関数名>(){ 任意の処理 }`
シェルの変数は基本グローバルであるため、関数内のみで使用したい場合は`local`を付けること

```shell
#! /bin/bash

# 実は意味のない関数
function set_name() {
    local name=$1     # name変数のスコープはset_nameの中だけになる
}

set_name 'Tanaka'     # 呼び出すときは()は不要
```

## 標準入力
　ここまできたら標準入力で変数に値を入れたいこともあるだろう。そんな時は`read`コマンドを使う。

```shell
#! /bin/bash

ls -la
read -p 'どのファイルを削除しますか?： ' filename    # 変数'filename'に標準入力から値を入れる
if [ -f $filename ];                               # ファイルが存在する場合
then
    rm $filename
    echo '${filename}を削除しました'
    exit 0
else;
    echo 'そのような名前のファイルは存在しません'
    exit 1
fi
```

## そのほか
　シェルスクリプトにはそのほかにもいろいろな機能がある。詳しくはここで書かないので、気になる方は自分で調べてみてください。~~決して書くのが力尽きたわけではない。~~

- for文,while文
    - いわずと知れたループコンビ
- 配列
    - ↑のループとうまく組み合わせると便利
- case文
    - 場合分けに便利
    - エラーコードを捌いて記録するときによく使う
- trap
    - 終了したときや`Ctrl + z`で停止させたときなどの処理を書ける
    - エラー処理で非常に重要
- select
    - 準備した選択しの中から選べるようにできる

# おわりに
　初めての投稿だけあって、かなり気合の入った記事になってしまった(あまりの文量に、最後のほうは力尽きてしまったが…)。サーバーレスが流行っているこのご時世でも、シェルスクリプトが役に立つ場面はとても多いと感じた。ルーティンワークはすべてコンピュータに投げてしまって、自分たちはじっくりと別なことをしていきたいですね。

# 参考記事

- https://qiita.com/kaw/items/ffdaf5d23627c0bd7e87
- https://wa3.i-3-i.info/word14689.html
- https://qiita.com/a_yasui/items/ec4f75b300410af8958d
- https://eng-entrance.com/linux-shellscript-operator