logo hsb.horse
← Retour au blog

Blog

Exécutez un script d'exécution périodique avec macOS Launchd

Comment créer un script qui s'exécute toutes les minutes comme Cron sur macOS Launchd. Instructions de configuration qui évitent les problèmes de variables d'environnement et incluent la gestion des journaux.

Publié: Mis à jour:

Utilisez macOS Launchd pour créer un script qui s’exécute périodiquement comme Cron. Étant donné que la configuration des variables d’environnement est fastidieuse, nous utilisons une méthode qui minimise les paramètres côté plist.

La configuration est la suivante.

plist → wrapper shell → main shell

Script d’emballage

Définissez les variables d’environnement, exécutez le script réel et redirigez vers le journal.

#!/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"

paramètres du plist

Réglé pour s’exécuter toutes les minutes.

<?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>

Script de configuration

Automatisez la configuration complète.

#!/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"