shellスクリプト覚え書き(bash)

# shellスクリプト覚え書き
書くたびに覚えておこうと思いつつ、つい忘れてしまうshellスクリプト。
完全に備忘録です。
この記事は、継続的に編集していきます。

# 1. 無限ループ、分岐、算術演算
shellスクリプトにおける無限ループ、分岐、変数を算術演算する方法。
```bash:無限ループ
# --------------------------------------
# 無限ループ
# --------------------------------------
while :
do
	# 変数宣言
	cnt=0
	# --------------------------------------
	# 無限ループを途中で脱出する
	# --------------------------------------
	while :
	do
		echo "ループ"$cnt"回目"
		# --------------------------------------
		# ifを使って分岐を作る
		# かっことかの間は必ず空白を入れる
		# --------------------------------------
		if [ $cnt -ge 3 ]; then
			echo "ループを終了します。"
			break
		fi

		# --------------------------------------
		# シェルの変数を算術演算する
		# --------------------------------------
		cnt=(( cnt + 1 ))
	done
done
```
# 2. CSVファイルの読み込み
CSVファイルを読み込んで、中身全てを処理する方法。

	# ------------------------------------------
	# CSVファイルを読み込んで中身を全て表示する
	# ファイルの中身ループはwhileにパイプする
	# ------------------------------------------
	IFS=','
	cat target.csv | while read line
	do
		# ----------------------------------------------------
		# 文字列のsplitにはsetを使う
		# splitの区切り文字は「IFS」という変数にセットしておく
		# ----------------------------------------------------
		set -- ${line}
		echo "1つ目:"$1"2つ目:"$2"3つ目:"$3
	done

# 3. ヒアドキュメント
ヒアドキュメントとは、shellスクリプト内で、ちょっとしたプログラムを起動して、そのプログラム中に実行する命令を動ファイル内に記述する方法です。
正確にはそういう意味の言葉ではありませんが、一応今はそのように解釈します。
このサンプルは、shellスクリプト内でSQL*Plusを起動して、DBからデータを取得する処理です。
```bash:ヒアドキュメント
#!/bin/sh

echo "ヒアドキュメントのサンプルです。"

# ここからヒアドキュメント
sqlplus /nolog >&/dev/null << EOF

conn scott/tiger@CRCL

# SQLエラーの時は終了コード:9で終了
whenever sqlerror exit 9

select SYSDATE from DUAL;

exit

EOF

if [ $? -ne 9 ]; then
	echo "正常終了"
else
	echo "SQL実行中にエラー"
fi
```
# 4. プロセスの存在確認→終了
常駐系のプロセスを定時で停止したり、起動後にプロセスの存在を確認する時のやり方です。
```bash:プロセスの存在確認
#!/bin/sh

# -------------------------------------------------------------
# まずはプロセスの存在チェックをする。
# プロセスの数をカウントして、結果が0でない場合、存在すると判定する。
# 「a.out」の部分は、チェックしたいプロセス名に置き換えて使用する。
# -------------------------------------------------------------
count=`ps -ef | grep a.out | grep -v grep | wc -l`
if [ $count = 0 ]; then
	echo "プロセスが存在しません。"
else
	echo "プロセスが存在します。"
fi

echo "1秒後、プロセスを終了します。"
sleep 1s

# ------------------------------------------------
# 起動中のプロセスを終了する。
# psでプロセスをgrepするところまでは同じ。
# 最後は結果の数をカウントするのではなく、
# 「awk」を使用してプロセスを終了する。
# ------------------------------------------------
ps -ef | grep a.out | grep -v grep | awk '{ print "kill -9", $2 }' | sh

# ------------------------------------------------
# プロセス終了後に再度プロセスの存在チェック。
# プロセスが停止していることをチェックする。
# ------------------------------------------------
count=`ps -ef | grep a.out | grep -v grep | wc -l`
if [ $count = 0 ]; then
    echo "プロセスが存在しません。"
else
    echo "プロセスが存在します。"
fi
```
# 5. 他サーバのプロセスの死活監視
他サーバでのプロセスを死活監視し、生存が確認できない場合、自サーバでプロセスを起動するやり方です。
簡易的にですが、障害時のフェイルオーバーのような仕組みが実現できます。
```bash:他サーバのプロセス監視
#!/bin/sh

# ----------------------------------------------------
# 他サーバで動いているプロセスを監視し、
# 生存が確認できない場合は自サーバでプロセスを起動する。
# ----------------------------------------------------
targetProccess="死活監視対象のプロセス"
targetHost="監視対象ホスト"
user="監視対象ホストのユーザ"

count=0

# --------------------------------------------------------
# サーバとプロセスに対して死活監視を行い、
# 累計3回失敗している場合には、自サーバでプロセスを起動する。
# --------------------------------------------------------
while [ 1 ]
do
	# --------------------------------------------
	# 3回以上生存確認に失敗している場合
	# --------------------------------------------
	if [ ${count} -ge 3 ]; then
		echo "累計3回の生存確認に失敗したので、プロセスを起動します。"
		exit 0
	fi

	# --------------------------------------------
	# サーバ自体が稼働していることをpingで確認する。
	# --------------------------------------------
	ping ${targetHost} -c 1 > /dev/null

	# --------------------------------------------
	# pingが失敗している場合
	# --------------------------------------------
	if [ $? != 0 ]; then
		echo "対象サーバping不通`expr ${count} + 1`回目"
		count=`expr $count + 1`;
		sleep 10
		continue
	fi

	# --------------------------------------------
	# 監視対象サーバにリモートシェルを実行し、
	# プロセスの生存確認を行う。
	# 生存確認はpsコマンドを使用して行う。
	# --------------------------------------------
	rsh_count=`ps -ef | grep a.out | grep -v grep | wc -l`

	# --------------------------------------------
	# psの結果が0の場合
	# --------------------------------------------
	if [ $rsh_count = 0 ]; then
	echo "対象プロセス未稼働検知`expr ${count} + 1`回目"
		count=`expr $count + 1 `;
		sleep 10
		continue
	fi

	echo "対象プロセスの生存確認しました。"
	count=0
	sleep 10
done
```
# おまけ. viの忘れがちなコマンド集
shellスクリプトとか、全然関係ありませんが、viのついつい忘れがちなコマンドのまとめです。
shellスクリプトをいじる時、十中八九viでいじってるはずなので。

|コマンド|結果|
|:--|:--|
|gg|ファイルの先頭まで移動|
|G|ファイルの末尾まで移動|
|w|1つあとの単語に移動|
|b|1つ前の単語に移動|
|dw|カーソル位置から空白を含む単語の末尾まで削除|
|de|カーソル位置から空白を含まない単語の末尾まで削除|
|d$|カーソル位置から行末まで削除する。|
|d0|行先頭からカーソル位置まで削除|
|/|文字列の検索(順方向)|
|?|文字列の検索(逆方向)|
|：%s/置換前文字列/置換後文字列/gc|文字列の置換(確認あり) ※区切り文字は「/」でなくてもOK