macOS Launchdを使って、Cronのように定期実行するスクリプトを構築する。 環境変数の整備が面倒なので、plist側の設定は最小にする方式をとる。
構成は以下の通り。
plist → wrapper shell → main shellラッパースクリプト
環境変数を設定し、実際のスクリプトを実行してログにリダイレクトする。
#!/bin/bash
# XDG環境変数の設定export XDG_STATE_HOME="${XDG_STATE_HOME:-$HOME/.local/state}"
# ログディレクトリの作成LOG_DIR="$XDG_STATE_HOME/cron-like"mkdir -p "$LOG_DIR"
# 実際のスクリプトを実行してログにリダイレクトexec "$HOME/.local/bin/cron-like/every-minute.sh" \ >> "$LOG_DIR/stdout.log" 2>> "$LOG_DIR/stderr.log"plist設定
毎分実行する設定。
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict> <key>Label</key> <string>localhost.cron.every-minute</string> <key>ProgramArguments</key> <array> <string>/bin/bash</string> <string>/Users/username/.local/bin/cron-like/launchd.sh</string> </array> <key>StartInterval</key> <integer>60</integer> <key>RunAtLoad</key> <true/></dict></plist>セットアップスクリプト
一通りのセットアップを自動化する。
#!/bin/bash
set -e
# ディレクトリの作成mkdir -p "$HOME/.local/bin/cron-like"mkdir -p "$HOME/.local/state/cron-like"mkdir -p "$HOME/Library/LaunchAgents"
# ラッパースクリプトの作成cat > "$HOME/.local/bin/cron-like/launchd.sh" <<'EOF'#!/bin/bash
# XDG環境変数の設定export XDG_STATE_HOME="${XDG_STATE_HOME:-$HOME/.local/state}"
# ログディレクトリの作成LOG_DIR="$XDG_STATE_HOME/cron-like"mkdir -p "$LOG_DIR"
# 実際のスクリプトを実行してログにリダイレクトexec "$HOME/.local/bin/cron-like/every-minute.sh" \ >> "$LOG_DIR/stdout.log" 2>> "$LOG_DIR/stderr.log"EOF
# 実行スクリプトの作成cat > "$HOME/.local/bin/cron-like/every-minute.sh" <<'EOF'#!/bin/bash
# 実際の処理echo "[$(date '+%Y-%m-%d %H:%M:%S')] Running every-minute task"
# ここに実際の処理を記述EOF
# 実行権限の付与chmod +x "$HOME/.local/bin/cron-like/launchd.sh"chmod +x "$HOME/.local/bin/cron-like/every-minute.sh"
# plistの作成LABEL="localhost.cron.every-minute"PLIST_PATH="$HOME/Library/LaunchAgents/${LABEL}.plist"
cat > "$PLIST_PATH" <<EOF<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict> <key>Label</key> <string>${LABEL}</string> <key>ProgramArguments</key> <array> <string>/bin/bash</string> <string>$HOME/.local/bin/cron-like/launchd.sh</string> </array> <key>StartInterval</key> <integer>60</integer> <key>RunAtLoad</key> <true/></dict></plist>EOF
# 構文チェックplutil -lint "$PLIST_PATH"
# 既にロードされている場合はアンロードlaunchctl list | grep -q "$LABEL" && launchctl unload "$PLIST_PATH" 2>/dev/null || true
# ロードlaunchctl load "$PLIST_PATH"
echo "✓ Setup complete!"echo " Scripts: $HOME/.local/bin/cron-like/"echo " Logs: $HOME/.local/state/cron-like/"echo " plist: $PLIST_PATH"echo ""echo "Commands:"echo " tail -f $HOME/.local/state/cron-like/stdout.log"echo " launchctl start $LABEL"echo " launchctl unload $PLIST_PATH"
hsb.horse