現場でよく使うシェルコマンドを取りまとめるBashスクリプトの操作まとめ

# はじめに
デプロイ用スクリプトとか書いてます。
プログラムはPHPとかNode.jsで書くので、Bashで書くのはコマンドを取りまとめたものになります。
引数を渡したり、環境変数を定義させたりしつつ、シェルに対しての操作が多いです。
「Bash 書き方」とかでググるとBashスクリプト全般のことが出てくるのでちょっと趣旨がちがって、CIとかインフラ用に書くときにぐぐっていることのまとめです。

# よく書くパターン

```bash
#!/usr/bin/env bash
set -xe # -xで実行コマンドを表示、-eでエラーがあったときに終了
cd -- "$(dirname "$BASH_SOURCE")" # ファイルがある場所に移動
```

# Shebang
最初の行に書いておくやつ。シェバン。

```bash:test.sh
#!/usr/bin/env bash
```

> https://en.wikipedia.org/wiki/Shebang_(Unix)

# エラーなどの出力を出す
エラーのみ。

```bash:test.sh
set -e
```

コマンドも出力する。

```bash:test.sh
set -xe
```

# `set -x`したものを無効化する
`set -x`していると色々とデバッグメッセージが流れるので、無効化したいときは`+`オプションを使う。
`-x`に対しては`+x`。

```bash:test.sh
set -x # ここからデバッグ用の実行中コマンドが出力されます
echo 'hoge'

set +x # ここからデバッグ用の実行中コマンドの出力が無くなります。
```

> With set +e. Yeah, it's backward that you enable shell options with set - and disable them with set +. Historical raisins, donchanow.
[参考](https://stackoverflow.com/questions/3517162/how-to-undo-the-effect-of-set-e-which-makes-bash-exit-immediately-if-any-comm)

# 色付けする
`\e[34m`などのエスケープシーケンスで色がつきます。


```bash
printf '🎉\e[34m Success! \e[m🎉\n'
```

出力例

![image.png](https://qiita-image-store.s3.amazonaws.com/0/47327/0b418ef3-44db-f8d1-3671-e638b1c2d1f2.png)


# カレントディレクトリをスクリプトファイルがある場所に移動

```bash:test.sh
pwd -P # 確認用 /home/username
cd -- "$(dirname "$BASH_SOURCE")" # ここ
pwd -P # 確認用 /home/username/bin/test
```

# testを使った判定

本来`test`は数値判定に使われていたけど、シェルスクリプトとしての`test`は文字列操作、ファイル操作を主に使っているのでそこにフォーカス。

| オプション | 説明 | オプションの語源 |
|:-:|:-:|:-:|
| -z | 変数が空 | is **Z**ero |
| -n | 変数になにかある | is **N**umber | 
| -d | ディレクトリかどうか | is **D**irectory |
| -f | ファイルかどうか  | is **F**ile |
| -e | 存在するか | is **E**xisting |
| -r | 読めるか |  is **R**eadable |
| -w | 書けるか | is **W**ritable |
| -x | 実行できるか | is  e **X**ecutable |

https://shellscript.sunone.me/if_and_test.html

ググるときは「bash test file exsist」のように「bash test」と書くと良い。

## 変数が存在するか
基本的には`test`の`-z`で調べるらしいんだけど、-zの本来の意味はゼロかどうか。なので変数をダブルクォートで囲むと良い。

```bash:test.sh
HOGE='hoge desu yo'
FUGA=''

if [ -z "$HOGE" ]; then
    echo "HOGE is empty" # 🙅‍♂️ここに来ません
else
    echo "HOGE is ${HOGE}" # 🙆‍♂️こちらになります
fi


if [ -z "$FUGA" ]; then
    echo "FUGA is empty" # 🙆‍♂️こちらになります
else
    echo "FUGA is ${FUGA}" # 🙅‍♂️ここに来ません
fi
```

```bash:結果
$ bash test.bash
HOGE is hoge desu yo
FUGA is empty
```

> http://unix.stackexchange.com/questions/146942/how-can-i-test-if-a-variable-is-empty-or-contains-only-spaces


> https://stackoverflow.com/questions/18096670/what-does-z-mean-in-bash

## ディレクトリが存在するか

```bash
if [[ -d "path/to/target" ]]; then
  echo 'Directory exists'
  exit 1
fi
```

# 変数の展開
基本的には`$`と変数名。
例:)`$HOGE`
文字列が連続する場合に確実に展開させるには`$`の後に中括弧で変数名を書く。
例1:) `$HOGEFUGA` (これだと$HOGE + 'FUGA'なのか$HOGEFUGAなのか区別が付かない
例2:) `${HOGE}FUGA`

# 引数の処理 (Arguments)

1番目の引数を`$PROFILE`に代入。指定されていなければ `default` を代入。

```bash:test.sh
PROFILE=${1:-default}

echo $PROFILE
```

```
$ ./test.sh profile_desu
profile_desu
```


# 変数が定義されていれば○○
三項演算子的なあれです。

```bash:test.sh
HOGE=hoge
FUGA=${HOGE-fuga} # $HOGEは定義されているのでhogeが参照される
echo $FUGA # hoge

PIYO=${HOGE2-piyo} # $HOGE2は定義されていないのでpiyoが参照される
echo $PIYO; # piyo
```

# タブ文字などを出したい
`$`を使ってシェルに展開してもらう。

```bash
$ $'\t' # タブ文字が出る
$ echo 'mae'$'\t''usiro' # mae      usiro
```

先頭にタブ文字を追加する。

```bash
$ echo 'hoge' | sed -e 's/^/'$'\t''/g'
```

# curlのダウンロード
Bashスクリプトではないのですが、スクリプト内で使うコマンド。

```bash
curl -LOJ https://example.com
```

オプション | 説明
---|---
-L | リダイレクトをフォローする。（リダイレクトが合った場合に追跡して次のURLに自動でアクセスする）
-O | ファイルをそのまま保存させる。
-J | サーバから指定されたファイル名を保存時のファイル名として使う。このオプションが無いとURLの末尾をファイル名として使おうとするため、トークンやクエリパラーメータ付きのURL等のダウンロードの際に苦労します。


# ShellCheck
シェルの構文にエラーがないかチェックをすることができます。
手元でも行うことができますし、オンラインでも可能です。

https://www.shellcheck.net/