Shellの基礎知識(実践編)

【Shellの基礎知識】シェルスクリプトの作成を時短!テンプレートで効率化する方法

シェルスクリプトを作成する際、毎回似たような処理を記述することが多く、手間がかかります。特に、スクリプトのエラーハンドリングやログ出力の統一、環境変数の設定など、繰り返し発生する作業が多いのが現実です。

実際にサーバ構築の現場では、ベテランと新人エンジニアの間で、コードの品質以前に「作成に取り掛かるまでの時間」に大きな差があることがわかっています。これは単に面倒くさいからなのか、どこから手を付ければいいのか分からないのか、明確な理由は不明ですが、とにかく「着手するまでの時間」が驚くほど違うのが実情です。

中には、どう書き始めればよいか分からず、トイレにこもってしまうエンジニアも多く、その後必ず「何か参考になるスクリプトがあれば見せてください」と聞いてくる—— これはもはやコーダーあるある。様式美のようなものです。しかし、中には何もせずに考え続けたまま1日が終わってしまうケースも少なくありません。

このような状況を打破するために考えたのが、シェルスクリプト作成のテンプレート化です。スクリプトの骨組みを事前に準備することで、書き始める際の心理的ハードルを下げ、エンジニアが素早く作業に取り掛かれるようになります。

こうした無駄な時間を削減し、より効率的にスクリプトを開発できるのが「テンプレートファイル作成スクリプト (template.sh)」 です。本記事では、この template.sh を活用することで、スクリプト作成の手間を大幅に省き、一貫性のあるスクリプトを効率的に作成する方法を解説します。

運用自動化ツール

🟡 運用自動化ツール
📌 面倒な作業を一括効率化!シェルスクリプトで実現する運用自動化術
├─ 基本共通
| ├─【Shellの基礎知識】簡単なログ出力ロジックを作ってみました。
| ├─【Shellの基礎知識】シェルスクリプトの作成を時短!テンプレートで効率化する方法
| ├─【Shellの基礎知識】共通関数定義クラスの完全ガイド!設計から実践まで徹底解説
├─ 開発環境構築
| ├─【RHEL系Linux】開発サーバー初期設定スクリプトの完全自動化
| ├─【RHEL系Linux】Apache+Let's Encrypt 自動構築スクリプト|バーチャルホスト対応
| ├─【RHEL系Linux】Tomcatを自動インストール・設定するスクリプトの作成と活用法
| └─【RHEL系Linux】PostgreSQLを自動インストールするシェルスクリプトの使い方
└─ 運用・保守
  ├─【RHEL系Linux】任意サービスを簡単制御!汎用サービススクリプトの活用術
  ├─【RHEL系Linux】ファイルやログを自動圧縮する汎用スクリプトの実装と活用法
  ├─【RHEL系Linux】リソース(CPU・MEM)監視スクリプトで使用率・異常を検知する仕組み
  ├─【RHEL系Linux】中間ファイル連携を完全制御するファイル転送スクリプト
  ├─【RHEL系Linux】信頼性を重視した完了保証型ディレクトリ転送スクリプトの設計と実装
  ├─【RHEL系Linux】ディスク使用率を自動監視するシェルスクリプトの実装
  └─【RHEL系Linux】サーバーの障害検知と自動通知|systemdログ監視の実装例

テンプレートファイル作成スクリプトクラスの概要

テンプレートファイル作成スクリプトは、単独で使用するのではなく、共通ログ出力クラスやユーティリティ関数クラス と組み合わせることで、より洗練されたスクリプト開発を実現できます。

テンプレートファイル作成スクリプトの目的

テンプレートファイル作成スクリプトの目的は、シェルスクリプトの初期セットアップを自動化し、統一されたフォーマットで作成できるようにすることです。

これにより、エンジニアはゼロからスクリプトを書く必要がなくなり、スクリプトの品質や一貫性を向上させることが可能になります。

さらに、共通ログ出力クラスによる標準化されたログ出力や ユーティリティ関数クラスによる共通関数の活用と組み合わせることで、より実用的なスクリプトの作成が可能になります。

テンプレートの重要性と課題解決のポイント

テンプレートファイル作成スクリプトを活用することで、以下のような課題を解決できます。

ポイント

  1. エンジニアの作業を効率化:毎回ゼロから作成するのではなく、既存のテンプレートを活用することで作業時間を短縮。
  2. 「毎回ゼロから作らない」ための工夫:標準的な構成を持つテンプレートを利用することで、作業の抜け漏れを防止。
  3. シェルスクリプトの品質向上:例えば、set -e を導入することでスクリプトの異常終了を防ぎ、安全性を向上。

テンプレートスクリプトの設計の基本方針

テンプレートファイル作成スクリプト template.sh の設計は、以下の基本方針に基づいています。

基本方針

  1. スクリプト名のバリデーション
    template という名前のスクリプト作成を禁止し、明確な命名規則を推奨。
  2. ログ出力 (logger.shrc) の組み込み
    ログ出力を標準化し、エラー発生時のデバッグを容易に。
  3. ユーティリティ関数 (utils.shrc) の活用
    便利な共通関数を活用することで、スクリプトの記述量を削減。
  4. ロック機構を用いた並行実行の制御
    競合を防ぎ、スクリプトの安全な実行を保証。

このように テンプレートファイル作成スクリプトは、スクリプトの標準化と作業効率化を目的とし、実用的なシェルスクリプトの作成を支援するために設計されています。

設計書の構成と設計要素

テンプレートファイル作成スクリプト は、新しいシェルスクリプトを作成するためのスクリプトであり、統一されたフォーマットのスクリプトを自動生成する役割を持ちます。
このスクリプトの設計を明確にすることで、作成されるスクリプトの品質を維持し、運用の一貫性を確保することができます。

クラス設計の前提条件

テンプレートファイル作成スクリプトの設計において、以下の点を考慮する必要があります。

設計項目説明
動作環境RHEL 系 Linux 環境(CentOS, Rocky Linux, AlmaLinux など)
依存ファイルlogger.shrc, utils.shrc を読み込む設計
スクリプトの役割統一フォーマットのスクリプトを生成するための作成ツール
作成対象システム運用・管理向けのシェルスクリプト

使用する変数一覧

テンプレートファイル作成スクリプト で使用される主要な変数は以下の通りです。

変数名説明
SCRIPT_NAME作成するスクリプトの名前(引数として指定)
SCRIPT_FILE作成されるスクリプトのファイルパス
JOB_OK, JOB_WR, JOB_ERジョブのステータス管理用の定数(正常終了・警告・エラー)

作成されるスクリプトの構成

テンプレートファイル作成スクリプトによって生成されるスクリプトのフォーマットは以下のような構成を持ちます。

構成要素説明
ヘッダースクリプトの説明、変更履歴、利用方法など
共通関数の読み込みlogger.shrcutils.shrc. ./com/logger.shrc の形式で読み込む
ジョブ管理変数処理成功・失敗を管理するための変数定義(JOB_OK など)
メイン処理作成されたスクリプトが実際に実行する処理(テンプレートにはプレースホルダーが含まれる)
ログ出力logOut を利用したログ管理
エラーハンドリングエラー時に exitLog を使い適切に終了処理を行う

実装されている関数の詳細

作成されたテンプレートファイルには、以下の関数が実装されています。環境に合わせて自由にヒアドキュメントないをカスタマイズして作成してください。

関数名説明
checkArgs()引数チェックを行い、不足している場合はエラーを出力
checkConf()設定ファイルの存在確認と適切な構成のチェック
terminate()スクリプトの終了処理としてロック解除とログ出力を行う
logOut()logger.shrc を利用してログ出力を統一し、デバッグしやすくする
acquireLock()同時実行を防ぐためのロック処理を実装

このように、明確な設計ルールに基づいた テンプレートファイル作成スクリプト を活用することで、より堅牢でメンテナンスしやすいスクリプト開発が可能になります。

以下はテンプレートファイル作成スクリプトクラスのソースコードになります。

#!/bin/sh
#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
#
# Usage:
#     template.sh [ 作成スクリプト名 ] 
#     #  sh template.sh test
# Description:
#     引数で指定されたShellスクリプトのテンプレートを作成する。l
#
# Design documents
#     None
#
#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
# <変更履歴>
# Ver. 変更管理No. 日付        更新者       変更内容
# 1.0  PR-0001    2019/01/16 Bepro       新規作成
#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/

# 引数チェック
if [ $# -lt 1 ]; then
  echo "[ERROR] Missing argument: Please specify the name of the script to create."
  echo "Usage: $0 <script_name>"
  exit 1
fi

# スクリプト名の取得
SCRIPT_NAME=$1

# "template" を含む名前は禁止
if echo "$SCRIPT_NAME" | grep -q -e 'template'; then
  echo "[ERROR] Invalid script name: The name cannot contain the word 'template'."
  exit 1
fi

# スクリプトファイルのパス
SCRIPT_FILE="./${SCRIPT_NAME}.sh"

# カレントディレクトリの書き込み権限を確認
if [ ! -w . ]; then
  echo "[ERROR] The current directory is not writable. Cannot create files here."
  exit 1
fi

# スクリプトファイルの重複チェック
if [ -f "$SCRIPT_FILE" ]; then
  echo "[ERROR] The file '$SCRIPT_FILE' already exists."
  exit 1
fi

# ----------------------------------------------------------
# テンプレート内容をスクリプトファイルに書き込む
# ----------------------------------------------------------
cat << EOF > "$SCRIPT_FILE"
#!/bin/sh
#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
#
# Usage:
#    SCRIPT_NAME.sh
# 
# Description:
#    This script is auto-generated by template.sh.
#
# Design documents
#    None
#
#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
# <変更履歴>
# Ver. 変更管理No. 日付        更新者       変更内容
#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
. "\$(dirname "\$0")/../com/logger.shrc"
. "\$(dirname "\$0")/../com/utils.shrc"
#runAs       root \$*
#setLANG     utf-8

# Job status codes
JOB_OK=0  # Normal exit
JOB_WR=1  # Warning exit
JOB_ER=2  # Error exit
rc=JOB_ER

# ----------------------------------------------------------
# functions terminate
# ----------------------------------------------------------
terminate() {
  releaseLock
}

# ----------------------------------------------------------
# functions checkArgs
# ----------------------------------------------------------
checkArgs() {
  :
}

# ----------------------------------------------------------
# functions checkConf
# ----------------------------------------------------------
checkConf() {
  :
}

# ====== サンプルテンプレート設定ファイルの作成 ======

# ETC_PATH が未設定ならデフォルトパスを設定
if [ -z "\$ETC_PATH" ]; then
  ETC_PATH="/etc"
fi

# 必要ならディレクトリを作成
mkdir -p "\$ETC_PATH"

# サンプル設定ファイルの作成(既存のものはバックアップ)
TEMPLATE_FILE="\$ETC_PATH/template.cfg"

if [ -f "\$TEMPLATE_FILE" ]; then
  mv "\$TEMPLATE_FILE" "\${TEMPLATE_FILE}.bak_\$(date +%Y%m%d%H%M%S)"
fi

cat <<EOT > "\$TEMPLATE_FILE"
# テンプレート設定ファイル
テンプレート設定ファイル1 # サンプル
テンプレート設定ファイル2 # サンプル
EOT

# ----------------------------------------------------------
# pre-process
# ----------------------------------------------------------
scope="pre"

hostname=$(hostname -s)
os=$(uname -s)
temp_list="\$TEMPLATE_FILE"  # 作成された設定ファイルを temp_list にセット

startLog

logOut "INFO" args: ["\$@"]

if acquireLock; then
  logOut "INFO" successfully locked.
else
  abort could not acquire lock.
fi

trap "terminate" 0 1 2 3 15

checkArgs \$*
# ----------------------------------------------------------
# main-routine
# ----------------------------------------------------------
scope="main"

# 設定ファイルが存在するか確認
if [ ! -f "\$temp_list" ]; then
    logOut "ERROR" "Configuration file not found: \$temp_list"
    exitLog \$JOB_ER
fi

# Loop processing of target worth.
sed '/^#/d;/^[[:blank:]]*$/d' "\$temp_list" | while IFS= read -r line; do
    echo "DEBUG: Line read - [\$line]"
    logOut "DEBUG" "Loop started turn of [ \$line ]."

    if [ \$? -ne 0 ]; then
        logOut "ERROR" "Failed to [ \$line ]."
        exitLog \$JOB_ER
    fi
done

if [ \$? -eq 0 ]; then
  rc=\$JOB_OK
fi
# ----------------------------------------------------------
# post-process
# ----------------------------------------------------------
scope="post"

exitLog \$rc
EOF

# 作成後にスクリプト名を置換
sed -i "s/SCRIPT_NAME/${SCRIPT_NAME}/g" "$SCRIPT_FILE"
# ----------------------------------------------------------
# テンプレートの書き込み終了
# ----------------------------------------------------------

# ファイル作成の成功判定
if [ $? -ne 0 ]; then
  echo "[ERROR] Failed to create the template file '$SCRIPT_FILE'."
  exit 1
fi

# ファイルの存在確認(念のため)
if [ ! -f "$SCRIPT_FILE" ]; then
  echo "[ERROR] Template file '$SCRIPT_FILE' does not exist after creation."
  exit 1
fi

# ファイルの実行権限を付与
chmod +x "$SCRIPT_FILE"

# 実行権限の付与に失敗した場合
if [ $? -ne 0 ]; then
  echo "[ERROR] Failed to set executable permissions on '$SCRIPT_FILE'."
  exit 1
fi

# 成功メッセージ
echo "Template script '$SCRIPT_FILE' has been created successfully."

本スクリプトの利用により生じた、いかなる損害についても一切の責任を負わないものとします。また、損害賠償等の義務ついても、一切責任を負いません。

処理詳細

テンプレートファイル作成スクリプト は、新しいシェルスクリプトを作成するためのテンプレート生成スクリプトであり、統一されたフォーマットのスクリプトを効率的に作成する役割を持ちます。この処理詳細では、テンプレートファイル作成スクリプトの実行フロー と 作成されるスクリプトの動作フロー を明確に整理し、それぞれの処理の流れを説明します。

  1. 引数の検証(作成側スクリプトの処理)
  2. スクリプト名のバリデーション(作成側スクリプトの処理)
  3. スクリプトファイルの存在チェック(作成側スクリプトの処理)

<作成されるスクリプトの処理(ヒアドキュメント内の処理)>

  1. テンプレートスクリプトの作成(作成されるスクリプトの処理)

<作成側スクリプトの後処理>

  1. テンプレートスクリプトの変数置換(作成側スクリプトの処理)
  2. スクリプトの実行権限設定(作成側スクリプトの処理)
  3. 作成完了メッセージの出力(作成側スクリプトの処理)

実践的な利用方法とサンプルコード

シェルスクリプトの作成は、環境設定や共通処理の組み込みなど、毎回似たような作業が発生しがちです。template.sh を活用することで、スクリプトの雛形を統一し、開発効率を向上させることができます。

本章では、template.sh の基本的な使い方 から 作成されたスクリプトのカスタマイズ方法、具体的な利用ケースや導入によるメリット について詳しく解説します

基本的な使い方

template.sh は、新しいシェルスクリプトを作成するためのテンプレートスクリプトです。このスクリプトを利用することで、共通のフォーマットを適用し、エラーハンドリングやログ出力の標準化が可能になります。

ここでは、template.sh を実行して 新しいスクリプトを作成する手順 と、作成されたスクリプトの構成を理解し、どのようにカスタマイズすればよいのか を説明します。

作成側スクリプトの実行

template.sh を使用して新しいスクリプトを作成するには、以下のコマンドを実行します。

$ ./template.sh my_script

このコマンドを実行すると、カレントディレクトリに my_script.sh というスクリプトが作成されます。

作成側スクリプトの処理

この処理では、 template.sh によって以下の手順でスクリプトが作成されます。

  • 指定されたスクリプト名のバリデーションを行う(適切な名前かチェック)。
  • 既に同名のスクリプトが存在する場合、エラーを出力して終了する。
  • ヒアドキュメントを使用して、スクリプトの雛形(テンプレート)を作成する。
  • sed コマンドを利用し、作成されたスクリプト内のプレースホルダー(例: SCRIPT_NAME)を指定したスクリプト名に置換する。
  • 作成されたスクリプトに実行権限を付与し、作成完了のメッセージを出力する。

作成されたスクリプトの内容

作成後の my_script.sh の中身は以下のようになります。

#!/bin/sh
#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
#
# Usage:
#    my_script.sh
# 
# Description:
#    This script is auto-generated by template.sh.
#
# Design documents
#    None
#
#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
# <変更履歴>
# Ver. 変更管理No. 日付        更新者       変更内容
#_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
. "$(dirname "$0")/../com/logger.shrc"
. "$(dirname "$0")/../com/utils.shrc"
#runAs       root $*
#setLANG     utf-8

# Job status codes
JOB_OK=0  # Normal exit
JOB_WR=1  # Warning exit
JOB_ER=2  # Error exit
rc=JOB_ER

# ----------------------------------------------------------
# functions terminate
# ----------------------------------------------------------
terminate() {
  releaseLock
}

# ----------------------------------------------------------
# functions checkArgs
# ----------------------------------------------------------
checkArgs() {
  :
}

# ----------------------------------------------------------
# functions checkConf
# ----------------------------------------------------------
checkConf() {
  :
}

# ====== サンプルテンプレート設定ファイルの作成 ======

# ETC_PATH が未設定ならデフォルトパスを設定
if [ -z "$ETC_PATH" ]; then
  ETC_PATH="/etc"
fi

# 必要ならディレクトリを作成
mkdir -p "$ETC_PATH"

# サンプル設定ファイルの作成(既存のものはバックアップ)
TEMPLATE_FILE="$ETC_PATH/template.cfg"

if [ -f "$TEMPLATE_FILE" ]; then
  mv "$TEMPLATE_FILE" "${TEMPLATE_FILE}.bak_$(date +%Y%m%d%H%M%S)"
fi

cat <<EOT > "$TEMPLATE_FILE"
# テンプレート設定ファイル
テンプレート設定ファイル1 # サンプル
テンプレート設定ファイル2 # サンプル
EOT

# ----------------------------------------------------------
# pre-process
# ----------------------------------------------------------
scope="pre"

hostname=localhost
os=Linux
temp_list="$TEMPLATE_FILE"  # 作成された設定ファイルを temp_list にセット

startLog

logOut "INFO" args: ["$@"]

if acquireLock; then
  logOut "INFO" successfully locked.
else
  abort could not acquire lock.
fi

trap "terminate" 0 1 2 3 15

checkArgs $*
# ----------------------------------------------------------
# main-routine
# ----------------------------------------------------------
scope="main"

# 設定ファイルが存在するか確認
if [ ! -f "$temp_list" ]; then
    logOut "ERROR" "Configuration file not found: $temp_list"
    exitLog $JOB_ER
fi

# Loop processing of target worth.
sed '/^#/d;/^[[:blank:]]*$/d' "$temp_list" | while IFS= read -r line; do
    echo "DEBUG: Line read - [$line]"
    logOut "DEBUG" "Loop started turn of [ $line ]."

    if [ $? -ne 0 ]; then
        logOut "ERROR" "Failed to [ $line ]."
        exitLog $JOB_ER
    fi
done

if [ $? -eq 0 ]; then
  rc=$JOB_OK
fi
# ----------------------------------------------------------
# post-process
# ----------------------------------------------------------
scope="post"

exitLog $rc

本スクリプトの利用により生じた、いかなる損害についても一切の責任を負わないものとします。また、損害賠償等の義務ついても、一切責任を負いません。

作成されたスクリプトのカスタマイズ

作成された直後のスクリプト内部には、このままでは何も機能しません。また、内部ロジックとしてサンプルのソースが記載されていますが、実際に使用する際に正しいソースコードに書き換えて使用してください。こんな感じという体で記載しているだけです。

[root@localhost bin]# sh template.sh my_script
Template script './my_script.sh' has been created successfully.
[root@localhost bin]# sh my_script.sh 
2025-01-30 21:15:28 [ INFO ] SCRIPT:[my_script.sh] PID:[331462] STARTED LOG.
2025-01-30 21:15:28 [ INFO ] args: []
2025-01-30 21:15:28 [ INFO ] Lock acquired on [/work/scripts//tmp/my_script.lock].
2025-01-30 21:15:28 [ INFO ] successfully locked.
DEBUG: Line read - [テンプレート設定ファイル1 # サンプル]
DEBUG: Line read - [テンプレート設定ファイル2 # サンプル]
2025-01-30 21:15:28 [ INFO ] Lock released: [/work/scripts//tmp/my_script.lock]

それらしく実行結果が出ていますが、サンプルソースのため何も機能は実施されません。

よく読まれている記事

1

「私たちが日々利用しているスマートフォンやインターネット、そしてスーパーコンピュータやクラウドサービス――これらの多くがLinuxの力で動いていることをご存じですか? 無料で使えるだけでなく、高い柔軟 ...

2

Linux環境でよく目にする「Vim」という名前。サーバーにログインしたら突然Vimが開いてしまい、「どうやって入力するの?」「保存や終了ができない!」と困った経験をした人も多いのではないでしょうか。 ...

3

ネットワーク技術は現代のITインフラにおいて不可欠な要素となっています。しかし、ネットワークを深く理解するためには、その基本となる「プロトコル」と「レイヤ」の概念をしっかり把握することが重要です。 こ ...

4

この記事は、Linuxについて勉強している初心者の方向けに「Shellスクリプト」について解説します。最後まで読んで頂けましたら、Shellスクリプトはどのような役割を担っているのか?を理解出来るよう ...

5

Javaは世界中で広く使われているプログラミング言語であり、特に業務システムやWebアプリケーションの開発において欠かせない存在です。本記事では、初心者向けにJavaの基礎知識を網羅し、環境構築から基 ...

-Shellの基礎知識(実践編)