script-development

Gaku52's avatarfrom Gaku52

スクリプト開発ガイド。Shell、Python、Node.jsスクリプト、自動化、バッチ処理、環境変数管理など、効率的なスクリプト開発のベストプラクティス。

⭐1stars🔀0forks📁View on GitHub🕐Updated Jan 3, 2026

When & Why to Use This Skill

This Claude skill serves as a comprehensive guide for efficient script development across Shell, Python, and Node.js. It provides best practices for automation, batch processing, environment variable management, and robust error handling, enabling developers to create maintainable and high-performance scripts for various technical workflows.

Use Cases

  • Automating Repetitive Tasks: Streamline system maintenance, file manipulations, and routine administrative duties using optimized Shell or Python scripts.
  • DevOps and Deployment: Create reliable deployment pipelines and CI/CD scripts with strict error checking and environment-specific configurations.
  • Data Processing and Migration: Develop scripts to handle CSV/JSON data, perform database migrations, and automate API interactions using Python or Node.js.
  • CLI Tool Development: Build professional command-line interfaces with advanced argument parsing and logging capabilities for internal tooling.
namescript-development
descriptionスクリプト開発ガイド。Shell、Python、Node.jsスクリプト、自動化、バッチ処理、環境変数管理など、効率的なスクリプト開発のベストプラクティス。

Script Development Skill

📋 目次

  1. 概要
  2. いつ使うか
  3. Shell スクリプト
  4. Python スクリプト
  5. Node.js スクリプト
  6. 環境変数管理
  7. 実践例
  8. Agent連携

概要

このSkillは、スクリプト開発をカバーします:

  • Shell スクリプト - Bash/Zsh
  • Python スクリプト - 自動化、データ処理
  • Node.js スクリプト - TypeScript/JavaScript
  • 環境変数管理 - .env、dotenv
  • エラーハンドリング - 適切なエラー処理
  • ログ出力 - 実行ログ記録

📚 公式ドキュメント・参考リソース

このガイドで学べること: Shell/Python/Node.jsスクリプトの基本文法、自動化パターン、環境変数管理、エラーハンドリング 公式で確認すべきこと: 最新の言語機能、セキュリティベストプラクティス、パッケージのアップデート

主要な公式ドキュメント

関連リソース


いつ使うか

🎯 必須のタイミング

  • 繰り返し作業の自動化時
  • デプロイスクリプト作成時
  • データ移行スクリプト作成時
  • 定期実行バッチ作成時

Shell スクリプト

基本構文

#!/bin/bash

# 変数
NAME="John"
echo "Hello, $NAME"

# コマンドライン引数
echo "First arg: $1"
echo "All args: $@"
echo "Number of args: $#"

# 条件分岐
if [ "$1" = "production" ]; then
  echo "Production mode"
elif [ "$1" = "development" ]; then
  echo "Development mode"
else
  echo "Unknown mode"
fi

# ループ
for file in *.txt; do
  echo "Processing $file"
done

# 関数
function greet() {
  local name=$1
  echo "Hello, $name"
}

greet "Alice"

# エラーハンドリング
set -e  # エラー時に終了
set -u  # 未定義変数使用時にエラー
set -o pipefail  # パイプライン内のエラーを検知

# コマンド実行結果の取得
CURRENT_BRANCH=$(git branch --show-current)
echo "Current branch: $CURRENT_BRANCH"

実用例:デプロイスクリプト

#!/bin/bash

# deploy.sh
set -euo pipefail

ENV=${1:-development}

echo "🚀 Deploying to $ENV..."

# ビルド
echo "📦 Building..."
npm run build

# テスト
echo "🧪 Running tests..."
npm test

# デプロイ
if [ "$ENV" = "production" ]; then
  echo "🌍 Deploying to production..."
  ssh user@server 'cd /var/www && git pull && pm2 restart app'
else
  echo "🔧 Deploying to development..."
  ssh user@dev-server 'cd /var/www && git pull && pm2 restart app'
fi

echo "✅ Deploy complete!"

Python スクリプト

基本構文

#!/usr/bin/env python3

import sys
import os
from pathlib import Path

def main():
    # コマンドライン引数
    if len(sys.argv) < 2:
        print("Usage: script.py <file>")
        sys.exit(1)

    file_path = sys.argv[1]

    # ファイル存在確認
    if not Path(file_path).exists():
        print(f"Error: {file_path} does not exist")
        sys.exit(1)

    # ファイル処理
    with open(file_path, 'r') as f:
        content = f.read()
        print(f"File size: {len(content)} bytes")

if __name__ == "__main__":
    main()

argparse(推奨)

#!/usr/bin/env python3

import argparse
from pathlib import Path

def process_file(file_path: Path, output: Path | None, verbose: bool):
    if verbose:
        print(f"Processing {file_path}...")

    with open(file_path, 'r') as f:
        content = f.read()

    # 処理
    result = content.upper()

    if output:
        with open(output, 'w') as f:
            f.write(result)
        if verbose:
            print(f"Saved to {output}")
    else:
        print(result)

def main():
    parser = argparse.ArgumentParser(description='Process a file')
    parser.add_argument('input', type=Path, help='Input file path')
    parser.add_argument('-o', '--output', type=Path, help='Output file path')
    parser.add_argument('-v', '--verbose', action='store_true', help='Verbose output')

    args = parser.parse_args()

    if not args.input.exists():
        parser.error(f"{args.input} does not exist")

    process_file(args.input, args.output, args.verbose)

if __name__ == "__main__":
    main()

# 使用例:
# python script.py input.txt
# python script.py input.txt -o output.txt -v

データ処理スクリプト

#!/usr/bin/env python3

import pandas as pd
import argparse
from pathlib import Path

def process_csv(input_path: Path, output_path: Path):
    # CSV読み込み
    df = pd.read_csv(input_path)

    # データ処理
    df['total'] = df['price'] * df['quantity']
    df_filtered = df[df['total'] > 1000]

    # 出力
    df_filtered.to_csv(output_path, index=False)
    print(f"✅ Processed {len(df)} rows → {len(df_filtered)} rows")

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('input', type=Path)
    parser.add_argument('output', type=Path)
    args = parser.parse_args()

    process_csv(args.input, args.output)

if __name__ == "__main__":
    main()

Node.js スクリプト

基本構文(TypeScript)

#!/usr/bin/env ts-node

import { readFileSync, writeFileSync } from 'fs'
import { program } from 'commander'

program
  .name('process-file')
  .description('Process a file')
  .argument('<input>', 'Input file path')
  .option('-o, --output <path>', 'Output file path')
  .option('-v, --verbose', 'Verbose output')
  .action((input, options) => {
    if (options.verbose) {
      console.log(`Processing ${input}...`)
    }

    const content = readFileSync(input, 'utf-8')
    const result = content.toUpperCase()

    if (options.output) {
      writeFileSync(options.output, result)
      if (options.verbose) {
        console.log(`Saved to ${options.output}`)
      }
    } else {
      console.log(result)
    }
  })

program.parse()

// package.json
{
  "scripts": {
    "process": "ts-node src/process.ts"
  },
  "bin": {
    "process-file": "./dist/process.js"
  }
}

ファイル操作

import fs from 'fs/promises'
import path from 'path'

async function processFiles(dirPath: string) {
  try {
    // ディレクトリ内のファイル一覧取得
    const files = await fs.readdir(dirPath)

    for (const file of files) {
      const filePath = path.join(dirPath, file)
      const stat = await fs.stat(filePath)

      if (stat.isFile() && file.endsWith('.txt')) {
        // ファイル処理
        const content = await fs.readFile(filePath, 'utf-8')
        const processed = content.toUpperCase()

        await fs.writeFile(filePath, processed)
        console.log(`Processed: ${file}`)
      }
    }
  } catch (error) {
    console.error('Error:', error)
    process.exit(1)
  }
}

processFiles('./data')

API呼び出し

import axios from 'axios'

async function fetchUsers() {
  try {
    const response = await axios.get('https://api.example.com/users', {
      headers: {
        'Authorization': `Bearer ${process.env.API_TOKEN}`
      }
    })

    console.log(`Fetched ${response.data.length} users`)

    // CSVに出力
    const csv = response.data
      .map((user: any) => `${user.id},${user.name},${user.email}`)
      .join('\n')

    await fs.writeFile('users.csv', `id,name,email\n${csv}`)
    console.log('✅ Saved to users.csv')
  } catch (error) {
    console.error('Error:', error)
    process.exit(1)
  }
}

fetchUsers()

環境変数管理

.env ファイル

# .env
DATABASE_URL=postgresql://localhost:5432/mydb
API_KEY=your_api_key_here
NODE_ENV=development

Node.js(dotenv)

import 'dotenv/config'

console.log(process.env.DATABASE_URL)
console.log(process.env.API_KEY)

// 必須チェック
const requiredEnvVars = ['DATABASE_URL', 'API_KEY']

for (const envVar of requiredEnvVars) {
  if (!process.env[envVar]) {
    console.error(`Error: ${envVar} is not set`)
    process.exit(1)
  }
}

Python(python-dotenv)

from dotenv import load_dotenv
import os

load_dotenv()

DATABASE_URL = os.getenv('DATABASE_URL')
API_KEY = os.getenv('API_KEY')

# 必須チェック
required_env_vars = ['DATABASE_URL', 'API_KEY']

for env_var in required_env_vars:
    if not os.getenv(env_var):
        print(f"Error: {env_var} is not set")
        exit(1)

Shell

#!/bin/bash

# .envファイルを読み込み
if [ -f .env ]; then
  export $(cat .env | grep -v '^#' | xargs)
fi

echo "DATABASE_URL: $DATABASE_URL"

実践例

Example 1: データ移行スクリプト(Python)

#!/usr/bin/env python3

import psycopg2
from dotenv import load_dotenv
import os
import sys

load_dotenv()

def migrate_data():
    # 接続
    conn = psycopg2.connect(os.getenv('DATABASE_URL'))
    cur = conn.cursor()

    try:
        # データ移行
        cur.execute("""
            INSERT INTO new_users (id, name, email)
            SELECT id, name, email FROM old_users
            WHERE migrated = false
        """)

        # フラグ更新
        cur.execute("UPDATE old_users SET migrated = true")

        conn.commit()
        print(f"✅ Migrated {cur.rowcount} rows")

    except Exception as e:
        conn.rollback()
        print(f"❌ Error: {e}")
        sys.exit(1)

    finally:
        cur.close()
        conn.close()

if __name__ == "__main__":
    migrate_data()

Example 2: 定期バックアップスクリプト(Shell)

#!/bin/bash

# backup.sh
set -euo pipefail

BACKUP_DIR="/var/backups/db"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$BACKUP_DIR/backup_$DATE.sql.gz"

# ディレクトリ作成
mkdir -p "$BACKUP_DIR"

# バックアップ実行
echo "📦 Creating backup..."
pg_dump -U postgres mydb | gzip > "$BACKUP_FILE"

echo "✅ Backup saved: $BACKUP_FILE"

# 古いバックアップ削除(7日以上前)
find "$BACKUP_DIR" -name "backup_*.sql.gz" -mtime +7 -delete
echo "🗑️  Old backups deleted"

# crontabで毎日実行
# 0 2 * * * /path/to/backup.sh >> /var/log/backup.log 2>&1

Agent連携

📖 Agentへの指示例

Shell スクリプト作成

以下を行うShell スクリプトを作成してください:
1. GitHubから最新コードをpull
2. npmビルド実行
3. PM2でアプリ再起動
4. エラー時は通知

Python データ処理スクリプト作成

CSV ファイルを読み込み、以下の処理を行うPython スクリプトを作成してください:
- priceとquantityからtotalを計算
- total > 1000の行のみフィルタリング
- 結果を新しいCSV ファイルに出力

まとめ

スクリプト開発のベストプラクティス

  1. エラーハンドリング - set -e(Shell)、try-catch(Python/Node.js)
  2. 環境変数 - .envファイルで管理
  3. 引数パース - argparse(Python)、commander(Node.js)
  4. ログ出力 - 実行状況を記録

Last updated: 2025-12-24