bash コーディングルール

# 0. 始めに
シェルスクリプトを作成することが多くある為、個人的に気を付けている点をまとめます。

# 1. シェバン

bashを使用する場合は `/bin/sh` ではなく、 `/bin/bash` を使用する。

```bash
#!/bin/bash
```

↓↓↓↓↓↓↓ あなたの記事の内容
# 2. スクリプトが置かれているディレクトリパスの取得
───────
# 2. スクリプトが置かれているディレクトリの取得
↑↑↑↑↑↑↑ 編集リクエストの内容

上位ディレクトリの構成に依存せず動作できるようにする為、スクリプトが配置されているディレクトリを取得する。
※設定ファイルを `source` したりする場合に取得する必要がある。

```bash
readonly DIR_ROOT="$(cd "`dirname "${0}"`"; pwd)"
```

構成によっては `pwd` の前に `cd ..` を挟み、上位ディレクトリをスクリプトルートとする。

# 3. 変数
##  命名規則
### 定数
- 大文字とする
- `readonly` で宣言する。
- 単語と単語の間は `_` (アンダースコア)でつなぐ。
    - ex. DIR_ROOT

### 変数
- 小文字とする。
- 単語と単語の間は `_` (アンダースコア)でつなぐ。
- 関数内で宣言する場合は `local` を使用して宣言し、スコープを明確化する。

### ファイル、ディレクトリ名を格納する変数の命名規則
- 末尾に `/` をつけない。

|対象                       |命名例     |
|:--------------------------|:------------|
|ディレクトリ名（絶対・相対パス）|DIR_HOGE|
|ディレクトリ名（パスなし）|DIRNAME_HOGE |
|ファイル名（絶対・相対パス）|FILE_HOGE|
|ファイル名（パスなし）|FILENAME_HOGE|

```bash
# ディレクトリ名（絶対・相対パス）
readonly DIR_HOGE="/path/to/hoge"
# ディレクトリ名（パスなし）
readonly DIRNAME_HOGE="hoge"
# ファイル名（絶対・相対パス）
readonly FILE_HOGE="/path/to/hoge/fuga.conf"
# ファイル名（パスなし）
readonly FILENAME_HOGE="fuga.conf"
```


## 使用方法
- 変数使用時は以下の要領で `"${var}"` 必ず、ダブルクォーテションと波括弧で囲う。


```bash
if [ "${var}" -ne 0 ]; then
    echo "value is not 0."
else
    echo "value is 0."
fi
```

# 4. 関数
## 命名規則
- 小文字で宣言する。
- 単語同士を `_` で連結する。

## 宣言
- 以下の要領で宣言する。

```bash
function logger() {
    local msg="${2}"
    case "${1}" in
        "${CNS_INF}" )  local status="INFO "
                        ;;
        "${CNS_WRN}" )  local status="WARN "
                        ;;
        "${CNS_ERR}" )  local status="ERROR"
                        ;;
    esac
    echo "`date "+%Y/%m/%d-%H:%M:%S-%Z"` `hostname -s` `whoami` ${status} ${msg}"
}
```

※「開始波括弧の前で改行して開始と終了がそろうようにすべし」とする意見もあるが、どちらがメジャーなんだろう。。。

```bash
function hoge()
{
  echo "hoge"
}
```

# 5. 制御構文
ポイントのみ記載する。
## `if ~` 
- 検査対象の変数は**必ずダブルクォーテーションで囲む**。(万が一、変数が空の場合でも正常に動作させる為)
- `if` と `then` はセミコロンを利用し、1行に記載する。（`if` と `fi` のインデントをそろえ可読性を向上させる為）
- セミコロンと `then` の間は半角スペースを空ける。

```bash
if [ -w "${var}" ]; then
    echo "file is writeable."
fi
```

## `while ~` , `for ~`
- `for` or `while`文の終わりで改行し、 `do` を同一行に記載しない。（`do` と `done` のインデントをそろえ可読性を向上させる為）
- ループの中で変数の値を変更し、ループ外から参照する必要がある場合は **`for`** を選択する。（`while`だと、参照できない）

```bash
status=0
for files in `cat "${files}" | grep -v -e '^\s*#' -e '^\s*$'`
do
    rm -fv files
    status="$(( ${status} + ${?} ))"
done
echo "${status}"
```

※`grep -v -e '^\s*#' -e '^\s*$'` : コメントアウト、空行を読み飛ばす。


# 6. その他
## リダイレクト
- リダイレクトの書き方
コマンドの終わりと `>` の間は半角スペースを空け、ファイル名との間はスペースを空けない。

```bash
echo "This is test." >"${FILE_LOG}" 2>&1
```

- 複数の標準・エラー出力をファイルへリダイレクトするときはまとめる。

```bash
{
date ""
date "+%Y/%m/%d-%H:%M:%S-%Z"
echo "Output to log file."
} 2>&1 | tee "${FILE_LOG}"
```

※コマンドへパイプしているが、当然 `} >"${FILE_LOG}" 2&1` としても動作する。

## 変数の利用
- 以下のような場合は必ずシングルクォーテーション、もしくは、ダブルクォーテーションで囲む。
    - 変数へ文字列を格納する
    - 変数を関数へ引数として渡す場合
    - コマンドのオプションとして渡す場合

```bash
# 変数へ文字列を格納する
var="hoge-$(date "+%Y/%m/%d")"
# 変数を関数へ引数として渡す場合
fuga_function "${var}"
# コマンドのオプションとして渡す場合
sed -e 's/HOGE/GUFA/g' "${file}"
```

## `trap`
`trap` コマンドを利用することでスクリプトが終了した場合に必ず行いたい処理を**必ず**実行できる。

例として多重処理防止用にロックファイルを作成し、終了時に必ず削除する場合の実装を記載する。

```bash
# 終了時に行いたい処理（終了処理）を関数としてまとめておく。
# trap の引数にコマンドを書くこともできるが、たいていの場合、複数の処理を行う為、関数化する。
function exit_proc() {
    # ロックファイルを削除する。
    rm -f "${FILE_LOCK}"
}
```

```bash
# 主処理開始
# trap で終了時に終了処理を呼び出すようにする。
trap exit_proc EXIT

# ロックファイルを作る。
ln -s "${FILE_TARGET}" "${FILE_LOCK}"
# 別プロセスでシンボリックリンクが作成されている場合、コマンドがエラーとなる。
if [ "${?}" -ne 0 ]; then
   echo "Another process is runnig."
   exit 1
fi

```
---
随時更新