0. 始めに

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

1. シェバン

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

#!/bin/bash

↓↓↓↓↓↓↓ あなたの記事の内容

2. スクリプトが置かれているディレクトリパスの取得

───────

2. スクリプトが置かれているディレクトリの取得

↑↑↑↑↑↑↑ 編集リクエストの内容

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

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

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

3. 変数

命名規則

定数

  • 大文字とする
  • readonly で宣言する。
  • 単語と単語の間は _ (アンダースコア)でつなぐ。
    • ex. DIR_ROOT

変数

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

ファイル、ディレクトリ名を格納する変数の命名規則

  • 末尾に / をつけない。
対象 命名例
ディレクトリ名(絶対・相対パス) DIR_HOGE
ディレクトリ名(パスなし) DIRNAME_HOGE
ファイル名(絶対・相対パス) FILE_HOGE
ファイル名(パスなし) FILENAME_HOGE
# ディレクトリ名(絶対・相対パス)
readonly DIR_HOGE="/path/to/hoge"
# ディレクトリ名(パスなし)
readonly DIRNAME_HOGE="hoge"
# ファイル名(絶対・相対パス)
readonly FILE_HOGE="/path/to/hoge/fuga.conf"
# ファイル名(パスなし)
readonly FILENAME_HOGE="fuga.conf"

使用方法

  • 変数使用時は以下の要領で "${var}" 必ず、ダブルクォーテションと波括弧で囲う。
if [ "${var}" -ne 0 ]; then
    echo "value is not 0."
else
    echo "value is 0."
fi

4. 関数

命名規則

  • 小文字で宣言する。
  • 単語同士を _ で連結する。

宣言

  • 以下の要領で宣言する。
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}"
}

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

function hoge()
{
  echo "hoge"
}

5. 制御構文

ポイントのみ記載する。

if ~

  • 検査対象の変数は必ずダブルクォーテーションで囲む。(万が一、変数が空の場合でも正常に動作させる為)
  • ifthen はセミコロンを利用し、1行に記載する。(iffi のインデントをそろえ可読性を向上させる為)
  • セミコロンと then の間は半角スペースを空ける。
if [ -w "${var}" ]; then
    echo "file is writeable."
fi

while ~ , for ~

  • for or while文の終わりで改行し、 do を同一行に記載しない。(dodone のインデントをそろえ可読性を向上させる為)
  • ループの中で変数の値を変更し、ループ外から参照する必要がある場合は for を選択する。(whileだと、参照できない)
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. その他

リダイレクト

  • リダイレクトの書き方 コマンドの終わりと > の間は半角スペースを空け、ファイル名との間はスペースを空けない。
echo "This is test." >"${FILE_LOG}" 2>&1
  • 複数の標準・エラー出力をファイルへリダイレクトするときはまとめる。
{
date ""
date "+%Y/%m/%d-%H:%M:%S-%Z"
echo "Output to log file."
} 2>&1 | tee "${FILE_LOG}"

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

変数の利用

  • 以下のような場合は必ずシングルクォーテーション、もしくは、ダブルクォーテーションで囲む。
    • 変数へ文字列を格納する
    • 変数を関数へ引数として渡す場合
    • コマンドのオプションとして渡す場合
# 変数へ文字列を格納する
var="hoge-$(date "+%Y/%m/%d")"
# 変数を関数へ引数として渡す場合
fuga_function "${var}"
# コマンドのオプションとして渡す場合
sed -e 's/HOGE/GUFA/g' "${file}"

trap

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

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

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

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


随時更新

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.