システム管理を効率化する Shell スクリプト実装例 7 選

1. 複数サーバーへの同時接続と応答時間計測

複数のホストに対して並列的に hostname を取得し、応答時間を記録します。処理完了後、最も応答が速かったサーバーの CPU 情報を取得します。

#!/usr/bin/env bash

TARGET_SERVERS=("192.168.1.10" "192.168.1.11" "192.168.1.12")
LOG_FILE="latency_report.log"

> "$LOG_FILE"

for server in "${TARGET_SERVERS[@]}"; do
(
    start=$(date +%s)
    ssh "$server" "hostname" >/dev/null 2&1
    sleep 2
    end=$(date +%s)
    duration=$((end - start))
    echo "$server: $duration" >> "$LOG_FILE"
)&
done

wait

fastest_host=$(sort -t: -k2 -n "$LOG_FILE" | head -1 | cut -d: -f1)
ssh "$fastest_host" "top -b -n 1 | head -10"

2. プロセス状態の統計とゾンビプロセス処理

/proc ディレクトリを走査し、プロセスの状態(Running, Stopped, Sleeping, Zombie)をカウントします。ゾンビプロセスを検出した場合は記録し、親プロセスを特定します。

#!/usr/bin/env bash

PID_LIST=$(ls /proc/ | grep -E '^[0-9]+$')

cnt_running=0
cnt_stopped=0
cnt_sleeping=0
cnt_zombie=0

for pid in $PID_LIST; do
    if [ -f "/proc/$pid/status" ]; then
        state=$(grep -E "^State" "/proc/$pid/status" | awk '{print $2}')
        case "$state" in
            R) ((cnt_running++)) ;;
            T) ((cnt_stopped++)) ;;
            S) ((cnt_sleeping++)) ;;
            Z)
                ((cnt_zombie++))
                echo "$pid" >> defunct_processes.log
                ppid=$(grep -E "^PPid" "/proc/$pid/status" | awk '{print $2}')
                echo "Zombie PID: $pid, Parent PID: $ppid" >> defunct_processes.log
                ;;
        esac
    fi
done

total=$((cnt_running + cnt_stopped + cnt_sleeping + cnt_zombie))
echo -e "Total: $total\nRunning: $cnt_running\nStopped: $cnt_stopped\nSleeping: $cnt_sleeping\nZombie: $cnt_zombie"

3. 文件拡張子の一括変更と行削除

当前ディレクトリ以下の `.sh` 文件を `.shell` に変更し、各文件の 2 行目を削除します。

#!/usr/bin/env bash

SCRIPT_FILES=$(find . -type f -name "*.sh")

for file in $SCRIPT_FILES; do
    base_name="${file%.sh}"
    new_name="${base_name}.shell"
    mv "$file" "$new_name"
    sed -i '2d' "$new_name"
done

4. 定期 jstack ダンプと旧ファイル削除

指定ディレクトリの管理を行い、1 時間ごとに Java プロセスの jstack 情報を保存します。ファイル数が 10 を超えた場合、最も古い文件を削除します。

#!/usr/bin/env bash

LOG_DIR='/var/log/jstack_dump'
TIMESTAMP=$(date +'_%Y%m%d_%H%M%S')

if [ ! -d "$LOG_DIR" ]; then
    mkdir -p "$LOG_DIR"
else
    rm -rf "${LOG_DIR}"/*
fi

cd "$LOG_DIR" || exit

while true; do
    sleep 3600
    target_pid=$(ps -ef | grep 'inceptor' | grep -v grep | awk '{print $2}')
    if [ -n "$target_pid" ]; then
        jstack "$target_pid" > "jstack${TIMESTAMP}.log"
    fi
    
    file_count=$(find . -type f | wc -l)
    if [ "$file_count" -gt 10 ]; then
        oldest=$(ls -tr | head -1)
        rm -f "$oldest"
    fi
done

5. GC ログの解析と統計

ログ文件から GC にかかった時間を抽出し、平均値と最大値を計算します。

#!/usr/bin/env bash

LOG_FILE="app_gc.log"
OUTPUT_FILE="gc_stats.log"

awk '{print $2}' "$LOG_FILE" | tr -d ':' | awk '{sum+=$1; count++} END {print "Average: ", sum/count}' >> "$OUTPUT_FILE"
awk '{print $2}' "$LOG_FILE" | tr -d ':' | awk 'BEGIN {max=0} {if ($1>max) max=$1} END {print "Max: ", max}' >> "$OUTPUT_FILE"

6. 接続数監視とアラート生成

特定ポートの接続数を監視し、上位 20 IP among の最小接続数が閾値を超えた場合、システム情報を記録します。

#!/usr/bin/env bash

monitoring=true

while $monitoring; do
    min_req=$(netstat -ant | awk -F'[ :]+' '/:80/{count[$4]++} END {for(ip in count) print count[ip]}' | sort -n | head -20 | tail -1)
    
    if [ "$min_req" -gt 500 ]; then
        sar -A > alert.txt
        monitoring=false
    else
        sleep 600
    fi
done

7. 大容量文件の移動とサイズ順表示

指定サイズ以上の文件を別ディレクトリに移動し、サイズ順にリスト表示します。

#!/usr/bin/env bash

ARCHIVE_DIR='/tmp'
SOURCE_DIR='.'

find "$SOURCE_DIR" -type f -size +10k -exec mv {} "$ARCHIVE_DIR" \;
ls -lS "$ARCHIVE_DIR" | awk 'NR>1 {print $NF}'

タグ: shell-scripting linux-automation bash system-monitoring log-parsing

8月29日 05:19 投稿