第3章:スクリプト言語による自動化の初歩

インフラエンジニアの業務において、日々の定型作業や繰り返し発生するタスクは少なくありません。例えば、サーバーの起動・停止、ログファイルの整理、バックアップの実行、特定の情報の収集などが挙げられます。これらの作業を手動で行うことは、時間と労力の無駄であるだけでなく、ヒューマンエラーの原因にもなります。ここで、スクリプト言語の知識が非常に重要になります。スクリプト言語は、簡単なコマンドの実行から複雑なロジックを伴う自動化まで、幅広い用途で活用できます。

この章では、インフラエンジニアが頻繁に利用するシェルスクリプトと、汎用性が高いPythonに焦点を当て、それぞれの基本的な使い方と自動化への応用方法を学びます。これらの言語を習得することで、日々の運用業務を効率化し、より重要度の高いタスクに時間を配分しやすくなります。

この章でできるようになること

  • シェルスクリプトの基本(作成・実行、変数、ファイル操作やテキスト処理などの基本コマンド、条件分岐やループなど)の前提を把握できる。
  • Python で「ファイル操作/外部コマンド実行/データ加工」などの自動化スクリプトを作るための基礎を説明できる。
  • 実務のタスクに対して、シェルスクリプトと Python の使い分けの観点を持てる。

スクリプト自動化アーキテクチャ

3.1 シェルスクリプトの基本

シェルスクリプトは、LinuxやUnix系OSのコマンドラインシェル(Bash, Zshなど)上で実行されるプログラムです。OSの標準コマンドを組み合わせて、ファイル操作、プロセス管理、システム設定の変更など、システムレベルの自動化を簡単に行うことができます。シンプルながらも強力なため、インフラの初期設定や簡易的な運用スクリプトとして広く利用されています。

スクリプトの作成と実行

シェルスクリプトは、テキストファイルにコマンドを記述し、実行権限を与えることで実行できます。

  1. スクリプトファイルの作成:
    テキストエディタでファイルを作成し、拡張子は.shとすることが多いですが必須ではありません。
    例: my_script.sh
  2. シバン(Shebang)の記述:
    スクリプトの先頭行に#!/bin/bashのような行を記述します。これは「シバン」と呼ばれ、このスクリプトをどのインタプリタ(シェル)で実行するかを指定します。
  3. 実行権限の付与:
    作成したスクリプトファイルに実行権限を与えます。
    chmod +x my_script.sh

  4. スクリプトの実行:
    ./my_script.sh

基本的なコマンド

シェルスクリプトは、普段ターミナルで手動で入力しているコマンドを羅列することで作成できます。

  • ls: ファイルやディレクトリの一覧表示
  • cd: ディレクトリの移動
  • pwd: 現在の作業ディレクトリの表示
  • mkdir: ディレクトリの作成
  • rm: ファイルやディレクトリの削除
  • cp: ファイルやディレクトリのコピー
  • mv: ファイルやディレクトリの移動または名前変更
  • cat: ファイルの内容表示
  • echo: 文字列の出力(変数の表示にもよく使われます)

変数

シェルスクリプトでは、データを一時的に保存するために変数を使用します。

  • ユーザー定義変数: スクリプト内で独自に定義する変数。変数名=値 の形式で定義し、$変数名 で参照します。変数名と=の間、および=と値の間にスペースを入れてはいけません。
  • 環境変数: OSによって設定され、システム全体で利用可能な変数(例: PATH, HOME, USER)。これらも$変数名で参照できます。
#!/bin/bash

# ユーザー定義変数の例
SERVER_NAME="web01"
LOG_DIR="/var/log/myapp"

echo "処理対象サーバー: $SERVER_NAME"
echo "ログディレクトリ: $LOG_DIR"

# 環境変数の例
echo "現在のユーザーのホームディレクトリ: $HOME"
echo "現在のユーザー名: $USER"

条件分岐

特定の条件に基づいて異なる処理を実行するために、if-fiやcase-esacを使用します。

  • if-fi:
    最も基本的な条件分岐の構文です。ifの後に条件式を記述し、thenの後に条件が真の場合の処理、elseの後に偽の場合の処理を記述します。fiでifブロックを閉じます。条件式は[と](または[[と]])で囲みます。
#!/bin/bash

FILE="test.txt"

if [ -f "$FILE" ]; then # -f はファイルが存在するかどうかをチェック
  echo "$FILE は存在します。内容を表示します。"
  cat "$FILE"
else
  echo "$FILE は存在しません。作成します。"
  touch "$FILE"
  echo "Hello from shell script!" > "$FILE"
  echo "$FILE を作成し、内容を書き込みました。"
fi

# 数値比較の例
NUM_USERS=10
if [ "$NUM_USERS" -gt 5 ]; then # -gt は Greater Than (より大きい)
  echo "ユーザー数は5人より多いです。"
elif [ "$NUM_USERS" -eq 5 ]; then # -eq は Equal (等しい)
  echo "ユーザー数はちょうど5人です。"
else
  echo "ユーザー数は5人以下です。"
fi
  • 主な条件演算子:
    • -f ファイル: ファイルが存在し、かつ通常ファイルである
    • -d ディレクトリ: ディレクトリが存在する
    • -e パス: ファイルまたはディレクトリが存在する
    • -z “文字列”: 文字列が空である
    • -n “文字列”: 文字列が空ではない
    • “文字列1” = “文字列2”: 文字列が等しい
    • “文字列1” != “文字列2”: 文字列が等しくない
    • -eq, -ne, -gt, -ge, -lt, -le: 数値の等しい、等しくない、より大きい、以上、より小さい、以下
  • case-esac:
    複数の選択肢の中から一つを実行する場合に便利です。
#!/bin/bash

read -p "サービス名を入力してください (web/db/exit): " SERVICE_NAME

case "$SERVICE_NAME" in
  "web")
    echo "Webサービスを起動します..."
    # systemctl start nginx
    ;;
  "db")
    echo "データベースサービスを起動します..."
    # systemctl start postgresql
    ;;
  "exit")
    echo "スクリプトを終了します。"
    exit 0 # 正常終了
    ;;
  *) # どのパターンにもマッチしない場合
    echo "不明なサービス名です: $SERVICE_NAME"
    echo "有効な入力は 'web', 'db', 'exit' です。"
    ;;
esac

ループ

繰り返し処理を行うために、forやwhileを使用します。

  • for:
    リストの要素を一つずつ処理したり、数値の範囲を反復処理したりする際に使います。
#!/bin/bash

# サーバーリストを処理
for SERVER in web01 web02 db01; do
  echo "サーバー $SERVER にSSH接続を試みます..."
  # ssh "$SERVER" "uptime" # 実際のコマンド
done

# 数値範囲のループ (Bash固有の機能)
echo "カウントダウン:"
for i in {5..1}; do
  echo "$i..."
  sleep 1 # 1秒待機
done
echo "発射!"
  • while:
    特定の条件が真である間、処理を繰り返します。
#!/bin/bash

COUNT=0
MAX_COUNT=3

echo "Whileループの開始:"
while [ "$COUNT" -lt "$MAX_COUNT" ]; do
  echo "現在のカウント: $COUNT"
  COUNT=$((COUNT + 1)) # 数値計算 (Bashの算術展開)
  sleep 0.5 # 0.5秒待機
done
echo "Whileループの終了。"

パイプとリダイレクト

コマンドの入出力を操作するために、パイプ(|)とリダイレクト(>>><)を使用します。これらはシェルスクリプトの強力な機能であり、複数のコマンドを連携させて複雑な処理を実現します。

  • パイプ (|): あるコマンドの標準出力を、別のコマンドの標準入力に渡します。

    # Debian/Ubuntu系: /var/log/syslog, RHEL系: /var/log/messages
    # systemd環境では journalctl(例: journalctl -p err --no-pager)も利用できます
    grep -i "error" /var/log/syslog | wc -l
    
  • リダイレクト (>): コマンドの標準出力をファイルに書き込みます。ファイルが存在する場合は上書きされます。

    echo "これは新しいログエントリです。" > /tmp/my_app.log
    cat /tmp/my_app.log
    
  • リダイレクト (>>): コマンドの標準出力をファイルの末尾に追記します。

    echo "これは追記されたログエントリです。" >> /tmp/my_app.log
    cat /tmp/my_app.log
    
  • リダイレクト (<): ファイルの内容をコマンドの標準入力として渡します。

    # input.txt の内容を cat コマンドの入力として渡す (cat input.txt と同じ結果になる)
    echo "Line 1" > input.txt
    echo "Line 2" >> input.txt
    cat < input.txt
    
  • 標準エラー出力のリダイレクト

    • 2>: 標準エラー出力をファイルに上書き。
    • 2>>: 標準エラー出力をファイルに追記。
    • &>: 標準出力と標準エラー出力を両方ファイルに上書き(bash依存。POSIX互換なら > file 2>&1)。
    • &>>: 標準出力と標準エラー出力を両方ファイルに追記(bash依存。POSIX互換なら >> file 2>&1)。
# 存在しないコマンドを実行し、エラーをファイルにリダイレクト
non_existent_command 2> error.log
cat error.log

関数

繰り返し利用する処理をまとめて関数として定義できます。これにより、スクリプトの可読性と再利用性が向上します。

#!/bin/bash

# 関数の定義
# 引数は $1, $2, ... でアクセスできる
log_message() {
  local MESSAGE="$1" # local でローカル変数として定義
  echo "[$(date +'%Y-%m-%d %H:%M:%S')] $MESSAGE"
}

# 関数の呼び出し
log_message "スクリプトを開始します。"
log_message "設定ファイルを読み込み中..."

# 例: Apache2 の稼働確認(必要なら再起動)
# systemctl status apache2 > /dev/null 2>&1
# if [ $? -eq 0 ]; then
#   log_message "Apache2 サービスは稼働中です。"
# else
#   log_message "Apache2 サービスは停止しています。再起動します。"
#   # systemctl restart apache2
# fi

log_message "スクリプトが正常に終了しました。"

localキーワードは、関数内で定義した変数がその関数内でのみ有効であることを示し、グローバル変数との衝突を避けるために重要です。

利用シーン

  • 簡単なバッチ処理、定期実行タスク(cron)
    • ログファイルのクリーンアップ(例: 7日以上前のログファイルを削除)。
    • 一時ファイルの削除。
    • 定期的なヘルスチェック(例: Webサーバーが応答するかを確認し、応答しない場合はアラートを送信)。
    • 簡易的なレポート生成(例: ディスク使用率やメモリ使用率を定期的に収集し、ファイルに書き出す)。
  • ログファイルのローテーション、バックアップスクリプト
    • logrotateの設定を補完したり、tarrsyncコマンドと組み合わせて、指定したディレクトリのファイルを圧縮・バックアップし、リモートストレージに転送するスクリプトを作成。
  • システムの状態確認、簡易的なヘルスチェック
    • df -h (ディスク使用量)、free -h (メモリ使用量)、ps aux (プロセス一覧) などのコマンド結果を整形して出力し、システムの状態を把握。
    • 特定のサービス(例: Nginx, MySQL)の起動状態を確認し、停止している場合は自動的に再起動する。
  • ユーザー管理の自動化
    • 新しいユーザーアカウントの作成、グループへの追加、SSHキーの配布など。

3.2 Pythonによる自動化の基礎

Pythonは、そのシンプルで読みやすい文法と、非常に豊富な標準ライブラリおよびサードパーティライブラリによって、インフラ自動化の分野で最も強力かつ汎用的なツールの一つとなっています。シェルスクリプトよりも複雑なロジックやデータ処理、API連携、そしてより大規模な自動化フレームワークの構築が必要な場合に特に威力を発揮します。

Pythonの環境構築(venvなど)

Pythonスクリプトを実行するには、まずPythonの実行環境が必要です。複数のプロジェクトで異なるバージョンのPythonやライブラリが必要になることを考慮し、プロジェクトごとに独立した環境を構築するために、仮想環境(Virtual Environment)の利用を推奨します。

  • Pythonのインストール
    • 多くのLinuxディストリビューションにはPythonがプリインストールされていますが、最新版や特定のバージョンが必要な場合は、公式サイトからインストーラーをダウンロードするか、OSのパッケージマネージャー(apt, yum, brewなど)を使ってインストールします。
    • Windowsでは、公式サイトからインストーラーをダウンロードして実行するのが一般的です。
  • 仮想環境(venv)の作成と利用
    • venvはPythonに標準で含まれる仮想環境作成ツールです。これにより、プロジェクトごとに必要なライブラリを分離し、システム全体のPython環境や他のプロジェクトの依存関係との衝突を防ぐことができます。
    # 仮想環境を作成したいディレクトリに移動
    cd my_project_directory
    
    # 仮想環境の作成 (my_automation_env は任意の仮想環境名)
    python3 -m venv my_automation_env
    
    # 仮想環境の有効化 (Linux/macOS)
    source my_automation_env/bin/activate
    # プロンプトの先頭に (my_automation_env) のような表示が出れば成功
    
    # 仮想環境の有効化 (Windows Command Prompt)
    # my_automation_env\Scripts\activate.bat
    
    # 仮想環境の有効化 (Windows PowerShell)
    # .\my_automation_env\Scripts\Activate.ps1
    
    # 仮想環境を抜ける
    deactivate
    
  • パッケージ管理ツール(pip)の基本
    • pipはPythonのパッケージ(ライブラリ)をインストール、アンインストール、管理するためのツールです。仮想環境を有効化している状態でpipコマンドを実行すると、その仮想環境内にパッケージがインストールされます。
    # パッケージのインストール (例: requestsとPyYAML)
    pip install requests PyYAML
    
    # インストール済みパッケージの確認
    pip list
    
    # 特定のパッケージのアンインストール
    pip uninstall requests
    
    # 現在の仮想環境にインストールされているパッケージとそのバージョンを
    # requirements.txt というファイルに書き出す (依存関係の管理に重要)
    pip freeze > requirements.txt
    
    # requirements.txt からパッケージをインストール (別の環境で同じ依存関係を構築する際など)
    pip install -r requirements.txt
    

基本的な文法(変数、リスト、辞書、関数)

Pythonの基本的なデータ構造と制御フローは、スクリプト作成の土台となります。これらは、第2章で学んだJSONやYAMLのデータ構造と密接に対応しています。

  • データ型(数値、文字列、ブール値)

    # 変数定義とデータ型
    name = "Alice"        # 文字列 (str)
    age = 30              # 整数 (int)
    height = 175.5        # 浮動小数点数 (float)
    is_admin = True       # ブール値 (bool)
    no_value = None       # 何もないことを表す (NoneType)
    
    print(f"名前: {name}, 型: {type(name)}")
    print(f"年齢: {age}, 型: {type(age)}")
    print(f"管理者: {is_admin}, 型: {type(is_admin)}")
    
  • リスト(配列)の操作
    • 順序を持つ要素の集まり。複数の項目をまとめて扱う際に便利です。ミュータブル(変更可能)なデータ型です。
    servers = ["web01", "web02", "db01"]
    print(f"サーバーリスト: {servers}")
    print(f"最初のサーバー: {servers[0]}") # インデックスは0から始まる
    print(f"最後のサーバー: {servers[-1]}") # 負のインデックスで後ろからアクセス
    
    servers.append("cache01") # 要素をリストの末尾に追加
    print(f"追加後: {servers}")
    
    servers.insert(1, "loadbalancer01") # 指定した位置に要素を挿入
    print(f"挿入後: {servers}")
    
    servers.remove("web02") # 指定した値をリストから削除
    print(f"削除後: {servers}")
    
    # リストの要素をループで処理
    for server in servers:
        print(f"現在のサーバー: {server}")
    
  • 辞書(マップ/ハッシュ)の操作
    • キーと値のペアの集まり。キーを使って値にアクセスします。順序はPython 3.7以降で挿入順序が保持されます。ミュータブルなデータ型です。
    server_info = {
        "name": "app01",
        "ip": "10.0.0.5",
        "os": "Ubuntu",
        "status": "running"
    }
    print(f"サーバー情報: {server_info}")
    print(f"OS: {server_info['os']}") # キーを指定して値にアクセス
    
    server_info["status"] = "stopped" # 既存のキーの値を更新
    print(f"更新後ステータス: {server_info['status']}")
    
    server_info["region"] = "ap-northeast-1" # 新しいキーと値を追加
    print(f"新しいキー追加後: {server_info}")
    
    del server_info["os"] # 要素を削除
    print(f"OS削除後: {server_info}")
    
    # 辞書のキー、値、またはペアをループで処理
    print("\nサーバー情報の詳細:")
    for key, value in server_info.items():
        print(f"  {key}: {value}")
    
  • 関数の定義と呼び出し、引数
    • 再利用可能なコードブロックを定義します。これにより、コードの重複を避け、可読性を高めることができます。
    def greet(name):
        """指定された名前に挨拶を返す関数"""
        return f"こんにちは、{name}さん!"
    
    message = greet("Bob")
    print(message)
    
    def calculate_disk_usage(total_gb, used_gb):
        """
        ディスク使用率を計算する関数。
        Args:
            total_gb (float): 総ディスク容量 (GB)。
            used_gb (float): 使用済みディスク容量 (GB)。
        Returns:
            float: ディスク使用率 (%)。総容量が0の場合は0を返す。
        """
        if total_gb == 0:
            return 0.0
        return (used_gb / total_gb) * 100.0
    
    usage = calculate_disk_usage(100, 45)
    print(f"ディスク使用率: {usage:.2f}%") # .2f で小数点以下2桁まで表示
    
    # デフォルト引数の例
    def log_message(message, level="INFO"):
        """ログメッセージを出力する関数"""
        print(f"[{level}] {message}")
    
    log_message("サービスが起動しました。")
    log_message("エラーが発生しました。", level="ERROR")
    
  • 条件分岐(if-elif-else)、ループ(for, while
    • プログラムの実行フローを制御します。
    # 条件分岐
    status = "stopped"
    if status == "running":
        print("サービスは稼働中です。")
    elif status == "stopped":
        print("サービスは停止しています。")
    else:
        print("不明な状態です。")
    
    # for ループ (リストの要素を順に処理)
    servers = ["web01", "web02", "db01"]
    for server in servers:
        print(f"処理中のサーバー: {server}")
    
    # while ループ (条件が真である間繰り返す)
    count = 0
    while count < 3:
        print(f"カウント: {count}")
        count += 1
    

ファイル操作、外部コマンド実行

Pythonは、ファイルシステムとのやり取りや、OSコマンドの実行も得意です。これにより、ログファイルの読み書き、設定ファイルの編集、外部ツールの呼び出しなどが可能になります。

  • ファイルの読み込み、書き込み with open(...) as f: の構文を使うと、ファイルが確実に閉じられるため推奨されます。encoding="utf-8"は、日本語などの文字化けを防ぐために重要です。

    import os
    
    file_path = "app_log.txt"
    
    # ファイルへの書き込み (w: 書き込みモード、ファイルが存在すれば上書き)
    try:
        # ファイルパスの検証(セキュリティ対策)
        if not file_path or '..' in file_path or file_path.startswith('/'):
            raise ValueError("不正なファイルパスが指定されました")
    
        # ディレクトリの存在確認と作成
        os.makedirs(os.path.dirname(file_path) if os.path.dirname(file_path) else '.', exist_ok=True)
    
        with open(file_path, "w", encoding="utf-8") as f:
            f.write("サーバー起動ログ\n")
            f.write("サービスAが正常に起動しました。\n")
            f.write("設定ファイルがロードされました。\n")
        print(f"'{file_path}' に内容を書き込みました。")
    except (OSError, IOError) as e:
        print(f"ファイル書き込みエラー: {e}")
    except ValueError as e:
        print(f"パス検証エラー: {e}")
    
    # ファイルからの読み込み (r: 読み込みモード)
    try:
        # ファイルの存在確認
        if not os.path.exists(file_path):
            raise FileNotFoundError(f"ファイルが見つかりません: {file_path}")
    
        # ファイルサイズの確認(大きすぎるファイルの読み込みを防ぐ)
        file_size = os.path.getsize(file_path)
        max_size = 10 * 1024 * 1024  # 10MB
        if file_size > max_size:
            raise ValueError(f"ファイルサイズが大きすぎます: {file_size} bytes")
    
        with open(file_path, "r", encoding="utf-8") as f:
            content = f.read() # ファイル全体を文字列として読み込む
            print(f"\n'{file_path}' の内容 (read):\n{content}")
    except (OSError, IOError) as e:
        print(f"ファイル読み込みエラー: {e}")
    except ValueError as e:
        print(f"ファイル検証エラー: {e}")
    
    # ファイルからの読み込み (行ごとに読み込む)
    print(f"\n'{file_path}' の内容 (readlines):")
    try:
        with open(file_path, "r", encoding="utf-8") as f:
            for line_num, line in enumerate(f, 1):
                print(f"  行{line_num}: {line.strip()}") # .strip() で行末の改行文字を削除
                # 無限ループを防ぐため、最大行数を制限
                if line_num > 1000:
                    print("  ... (1000行を超えるため省略)")
                    break
    except (OSError, IOError) as e:
        print(f"ファイル読み込みエラー: {e}")
    
    # ファイルへの追記 (a: 追記モード)
    try:
        # ファイルサイズの確認(ログファイルが大きくなりすぎないよう)
        if os.path.exists(file_path):
            file_size = os.path.getsize(file_path)
            max_size = 50 * 1024 * 1024  # 50MB
            if file_size > max_size:
                print(f"警告: ログファイルが大きすぎます ({file_size} bytes)")
    
        with open(file_path, "a", encoding="utf-8") as f:
            f.write("新しいログエントリが追加されました。\n")
        print(f"\n'{file_path}' に内容を追記しました。")
    except (OSError, IOError) as e:
        print(f"ファイル追記エラー: {e}")
    
    # クリーンアップ (演習後などにファイルを削除する場合)
    # if os.path.exists(file_path):
    #     os.remove(file_path)
    #     print(f"'{file_path}' を削除しました。")
    
  • subprocessモジュールを使った外部コマンドの実行 Pythonスクリプトの中から、シェルコマンドや外部プログラムを実行できます。これは、既存のCLIツールと連携したり、OSレベルの操作を行ったりする際に非常に便利です。

    import subprocess
    
    # コマンドを実行し、標準出力を取得 (capture_output=True, text=True で結果を文字列として取得)
    print("\n'ls -l' コマンドの実行結果:")
    try:
        result = subprocess.run(["ls", "-l"], capture_output=True, text=True, check=True)
        print(result.stdout)
    except subprocess.CalledProcessError as e:
        print(f"コマンド実行エラー: {e}")
        print(f"標準エラー出力:\n{e.stderr}")
    
    # エラーが発生するコマンドの例
    print("\n存在しないコマンドの実行結果 (エラーハンドリング):")
    try:
        error_result = subprocess.run(["non_existent_command"], capture_output=True, text=True, check=True)
        print(error_result.stdout)
    except subprocess.CalledProcessError as e:
        print(f"コマンド実行エラー: {e}")
        print(f"標準エラー出力:\n{e.stderr}")
        print(f"終了コード: {e.returncode}")
    except FileNotFoundError:
        print("エラー: コマンドが見つかりません。")
    
    # シェル経由でコマンドを実行 (shell=True)。セキュリティリスクに注意が必要
    # shell=True を使うと、シェルインジェクションのリスクがあるため、
    # ユーザーからの入力を直接コマンドに渡す場合は特に注意が必要です。
    # 基本的には shell=False でリスト形式でコマンドと引数を渡すのが安全です。
    
    # 安全な方法でpingコマンドを実行する例
    print("\n'ping -c 4 google.com' コマンドの実行結果 (安全な方法):")
    try:
        # タイムアウトを設定してハングを防ぐ
        result = subprocess.run(
            ["ping", "-c", "4", "google.com"],
            capture_output=True,
            text=True,
            check=True,
            timeout=30  # 30秒のタイムアウト
        )
        print(f"実行成功: {result.returncode}")
        print(f"出力: {result.stdout}")
    except subprocess.TimeoutExpired:
        print("エラー: コマンドがタイムアウトしました")
    except subprocess.CalledProcessError as e:
        print(f"コマンド実行エラー: {e}")
        print(f"標準エラー出力: {e.stderr}")
    except FileNotFoundError:
        print("エラー: コマンドが見つかりません")
    
    # 危険な例(本番環境では使用しない)
    # user_input = "google.com; rm -rf /"  # 悪意のある入力例
    # subprocess.run(f"ping -c 4 {user_input}", shell=True)  # 危険!
    
  • OSパス操作(os.path osモジュールは、オペレーティングシステムに依存する機能(ファイルパスの操作など)を提供します。

    import os
    
    # パスの結合 (OSに合わせて適切な区切り文字を使用)
    try:
        base_path = "/var/log/nginx"
        filename = "access.log"
    
        # パスの検証
        if '..' in base_path or '..' in filename:
            raise ValueError("不正なパス要素が含まれています")
    
        file_path = os.path.join(base_path, filename)
        print(f"結合されたパス: {file_path}")
    
        # パスの存在確認
        if os.path.exists(file_path):
            print(f"'{file_path}' は存在します。")
            # ファイルサイズの取得
            try:
                size = os.path.getsize(file_path)
                print(f"ファイルサイズ: {size} bytes")
            except OSError as e:
                print(f"ファイルサイズ取得エラー: {e}")
        else:
            print(f"'{file_path}' は存在しません。")
    
        # ディレクトリかどうかの判定
        test_dir = "/tmp"
        if os.path.exists(test_dir) and os.path.isdir(test_dir):
            print(f"'{test_dir}' はディレクトリです。")
        else:
            print(f"'{test_dir}' はディレクトリではありません。")
    
        # ファイルかどうかの判定
        test_file = "/etc/hosts"
        if os.path.exists(test_file) and os.path.isfile(test_file):
            print(f"'{test_file}' はファイルです。")
        else:
            print(f"'{test_file}' はファイルではありません。")
    except ValueError as e:
        print(f"パス検証エラー: {e}")
    except OSError as e:
        print(f"パス操作エラー: {e}")
    

利用シーン

  • クラウドAPI操作(SDKの利用)
    • AWS boto3、Azure SDK for Python、Google Cloud Client Libraries for Python など、各クラウドプロバイダーが提供するPython SDKを使って、Pythonからクラウドのリソースを操作します。これらのSDKは、内部的にAPIを呼び出すための便利なラッパーを提供しており、複雑な認証やリクエストの構築を抽象化してくれます。
    • 例えば、PythonスクリプトからEC2インスタンスを起動・停止したり、S3バケットを作成・管理したり、Azure VMをプロビジョニングしたりすることが可能です。
  • 複雑なデータ処理、ログ解析
    • 大量のログファイル(JSON形式のログなど)から特定のパターンを抽出し、集計・分析するスクリプトを作成します。
    • 複雑な階層を持つJSONやYAML形式の設定ファイルを読み込み、動的に値を変更したり、特定の条件に基づいて設定を生成したりします。
  • 設定ファイルの自動生成・更新
    • テンプレートエンジン(例: Jinja2)と組み合わせて、動的にサーバーの設定ファイル(Nginxの設定、Apacheのバーチャルホスト設定など)を生成します。
    • 既存の設定ファイルをPythonで読み込み、特定の値を更新して書き戻すことで、設定変更の自動化を実現します。
  • Webスクレイピング、レポート生成
    • Webサイトから情報を収集し(例: ニュースサイトから特定のキーワードを含む記事を抽出)、整形してレポートを作成します。
    • 複数の監視ツールやデータベースからデータを集約し、CSVやJSON形式で出力したり、グラフを生成したりする自動レポートスクリプトを作成します。
  • システムヘルスチェックと自動復旧
    • Webサービスのエンドポイントに定期的にリクエストを送信し、応答がない場合に自動的にサービスを再起動するスクリプト。
    • ディスク使用率を監視し、閾値を超えた場合に不要なファイルを削除したり、アラートを送信したりする。

3.3 実務での注意点

  • 破壊的な操作(例: rm、設定反映、リソース削除)は、対象を限定し、事前にバックアップ/ロールバック手順を用意します。
  • シェルスクリプトは、変数のクォート、終了コードの扱い、エラー時の停止(例: set -euo pipefail)を意識し、可能なら shellcheck 等で静的検査します。
  • Python は venv 等で実行環境を分離し、依存関係と実行手順を記録します(再現性の担保)。
  • ログや標準出力に秘密情報を出さない運用にします(マスキング/シークレット管理)。

まとめ

  • 定型作業の自動化は、作業時間の短縮だけでなく、ヒューマンエラーの削減にも直結する。
  • シェルスクリプトは OS の標準コマンドを組み合わせた自動化に強く、環境構築や簡易運用で有効になる。
  • Python は汎用性が高く、API 連携やデータ処理など「ロジックを持つ自動化」に向いている。
  • まずは小さなスクリプトから始め、作業手順をコード化して再現性を高める。

次章では、API の基礎と、Python を使った API 連携の実践に進みます。

次に読む