開発で使っていると、Macのストレージがじわじわ減っていきます。気づいたら「その他」だけで50GB超え。これ、キャッシュと一時ファイルが勝手に増殖している状態で、HomebrewやXcode、Dockerあたりが主犯格です。
私も数ヶ月に一度「あ、掃除しなきゃ」と思い出しては、手動でコマンドを叩いていました。ただ正直な話、3ヶ月持たずに忘れます。人間の意志力、マジで頼りにならない(笑)。
そこで今は、シェルスクリプト1本にメンテ処理をまとめて、macOS純正の launchd で毎週日曜の深夜に自動実行させています。設定してしまえば、もう掃除のことを考える必要がありません。
この記事では、実際に動かしているスクリプトとlaunchd設定をそのまま晒しつつ、自動化で事故らないための勘所までまとめます。
なぜMacの掃除をシェルで自動化するのか
結論、手動メンテはほぼ100%挫折するからです。Macのキャッシュは、見えるところに溜まってくれません。
Finderからじゃ存在に気づけない。だから放っておくと、ある日突然「ディスクの空き容量が残りわずかです」というダイアログが出て、そこで初めて「そういえば掃除してなかった…」となるパターン。
で、慌てて手動で掃除するわけですが、これを毎週続けるのは無理ゲーです。私も昔「月1でやろう」とカレンダーに入れていたのですが、3ヶ月目には完全にスルーするようになりました。
手動メンテは3ヶ月で必ず挫折する
理由はシンプルで、手動メンテにはリターンがほぼ見えないからです。掃除しても体感速度は変わらないし、容量が減ってもグラフが伸びるわけでもない。モチベが湧かないタスクを意志力で続けるのは、筋トレを続けるのと同じくらい難しいです。
シェル+launchdが「サボっても動く」最適解
じゃあどうするか。シェルスクリプトに処理をまとめて、launchdでスケジュールする。これが一番ラクです。cronでもいいじゃん、と思うかもしれませんが、macOSではlaunchdが公式の推奨方式。
スリープ復帰後にも確実に動くし、OS再起動でも生き残るので、ファイアアンドフォーゲットにできます。
Mac掃除シェルに入れたい5つの定番タスク
では実際、シェルに何を書くのか。私が使っているメンテ用スクリプトには、以下の5つを入れています。どれも「容量が目に見えて戻ってくる」定番処理なので、迷ったらこのセットから始めれば大丈夫です。
Homebrewのupdate・cleanup・autoremove
開発Macで一番容量を食うのがHomebrewです。brew cleanup で古いバージョンのバイナリを削除、brew autoremove で誰にも依存されなくなったパッケージを除去。
brew update
brew upgrade
brew cleanup -s
brew autoremovebrew doctor も走らせておくと、環境が壊れかけているタイミングで早めに気づけます。警告が出ても致命傷ではないので、ログにだけ残しておけば十分です。
Xcode DerivedDataとiOSシミュレータの整理
iOSアプリを触る人はこれが効きます。~/Library/Developer/Xcode/DerivedData はビルドするたびに肥大化するキャッシュで、放っておくと平気で20〜30GB食います。
rm -rf ~/Library/Developer/Xcode/DerivedData/*
xcrun simctl delete unavailable後者は、現行のXcodeがサポートしていない古いシミュレータを一括削除するコマンド。これも地味に効きます。
Dockerの未使用イメージとビルドキャッシュ削除
Dockerを使っていると、使い終わったイメージとビルドキャッシュが山のように残ります。docker system prune で一網打尽にできます。
docker system prune -f
docker builder prune -f-f フラグで確認プロンプトをスキップできるので、無人実行時はこれが必須です。付け忘れるとlaunchdでの実行が途中で止まります。
~/Library/Cachesの肥大化ファイルをdu -shで可視化
~/Library/Caches はアプリのキャッシュ置き場で、ここも肥大化します。ただ、全部消すとアプリの挙動が不安定になることがあるので、私は「可視化だけする」運用にしています。
du -sh ~/Library/Caches/* 2>/dev/null | sort -h | tail -20肥大化したキャッシュを上位20件だけログに出して、あとで目視チェックする流れ。全消ししないのは、Safariやメールのキャッシュを飛ばすと再構築で逆にCPUを食うからです。
ゴミ箱とDownloads配下の古いファイル整理
最後はゴミ箱とダウンロードフォルダ。空のゴミ箱は意識しないと溜まりっぱなしになるし、Downloadsは「あとで整理するフォルダ」と化している人が多いはず(私もそうでした)。
rm -rf ~/.Trash/*
find ~/Downloads -type f -mtime +90 -printDownloadsは「90日以上前のファイルを表示だけ」する運用にしています。自動削除すると「昨日保存した契約書が消えた」みたいな事故が起きるので、あくまで表示だけにとどめるのが安全です。
そのまま使えるシェルスクリプト実例
ここからは、実際に動いているスクリプトの中身を晒します。コピペで動く最小構成にしているので、まずはそのまま使ってみて、自分の環境に合わせて育てていく流れがおすすめです。
brew_update.shのミニマム版
まずはHomebrew専用のスクリプト。これだけでも週次で走らせておく価値があります。
#!/usr/bin/env bash
set -u
brew update
brew upgrade
brew cleanup -s
brew autoremove
brew doctor || true
brew missing || true
echo "brew update done: $(date)"set -e にしていないのは、brew doctor で警告が出て終了コードが非ゼロになっても続行したいからです。警告はあくまで参考情報として扱う方針にしています。
mac_clean.shで開発者向けキャッシュをまとめて掃除
もう1本、開発者向けキャッシュの整理スクリプトです。Xcode・Docker・キャッシュ可視化・ゴミ箱をひとつにまとめています。
#!/usr/bin/env bash
set -u
echo "[1/4] Xcode DerivedData"
rm -rf ~/Library/Developer/Xcode/DerivedData/*
xcrun simctl delete unavailable 2>/dev/null || true
echo "[2/4] Docker prune"
if command -v docker >/dev/null 2>&1; then
docker system prune -f
docker builder prune -f
fi
echo "[3/4] Cache visualization"
du -sh ~/Library/Caches/* 2>/dev/null | sort -h | tail -20
echo "[4/4] Trash"
rm -rf ~/.Trash/*
echo "mac_clean done: $(date)"dockerコマンドの存在チェックを入れているのは、Dockerが起動していないマシンでもスクリプトを使い回せるようにするため。複数台のMacで同じスクリプトを流用したいとき、この書き方が地味に効きます。
launchdで週次・月次に定期実行する設定手順
スクリプトができたら、次はlaunchdに登録します。ここが自動化の肝で、一度セットすれば本当に触ることがなくなります。
plistファイルの最小構成と書き方
launchdはplistというXMLファイルで設定します。~/Library/LaunchAgents に置く構成が一番ラクで、管理者権限もいりません。
<?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>com.example.mac-clean</string>
<key>ProgramArguments</key>
<array>
<string>/Users/you/scripts/mac_clean.sh</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Weekday</key><integer>0</integer>
<key>Hour</key><integer>4</integer>
<key>Minute</key><integer>30</integer>
</dict>
<key>StandardErrorPath</key>
<string>/tmp/mac_clean.err.log</string>
</dict>
</plist>Weekday=0で日曜、4時30分に起動。パスはフルパスで書く必要があります(~や$HOMEは展開されません)。ここで一度ハマると地味に時間を溶かすので要注意。
~/Library/LaunchAgentsへの配置とlaunchctl load
plistを配置したら、launchctlで読み込みます。これで登録完了。
cp com.example.mac-clean.plist ~/Library/LaunchAgents/
launchctl load ~/Library/LaunchAgents/com.example.mac-clean.plist
launchctl list | grep mac-clean3行目のlistで表示されれば登録できています。動作確認したいときは launchctl start com.example.mac-clean で手動実行できるので、スケジュール時刻を待たずにテストできます。
実行時間帯の分散テクニック
複数のスクリプトをlaunchdに登録していくと、全部同じ時刻に動かしたくなりますが、これはNGです。同時起動でCPUとディスクI/Oがピークに達して、スリープ復帰したMacが一瞬固まります。
| スクリプト | 頻度 | 実行時刻 |
|---|---|---|
| brew_update.sh | 週次(日) | 04:00 |
| mac_clean.sh | 週次(日) | 04:30 |
| dep_audit.sh | 週次(日) | 04:45 |
| venv_maintenance.sh | 月次(1日) | 05:30 |
こんな感じで日曜3:00〜5:00の15分刻みに散らしています。依存関係があるものだけ順番を意識して、あとは雑に散らせば十分です。
自動化で事故らないための3つの注意点
便利な反面、自動化は「静かに壊れる」リスクがあります。私が実際に踏んだ地雷を3つ紹介しておきます。先に知っておくだけで事故率はだいぶ下がります。
rm -rfは事前のls確認とドライランで守る
rm -rf は強力すぎます。一度、変数展開のミスで ~/Downloads を丸ごと消したことがあり、冷や汗をかきました。対策は、スクリプトに入れる前に必ず ls で対象を確認し、可能なら echo を頭に付けたドライランで出力を眺めること。
対話プロンプトが出るコマンドは完全無人実行に向かない
brew upgrade は一部パッケージでsudoパスワードを要求したり、mas コマンドがApple IDの認証を求めたりします。launchd経由だとプロンプトに応答できず、そこで止まります。私は対話が必要なコマンドはスクリプトから外して、手動実行用の別スクリプトにまとめる運用にしました。
ログ出力とSlack通知で「静かな失敗」を防ぐ
launchd実行のスクリプトは、失敗しても誰も気づきません。これが一番怖いポイント。私はスクリプト末尾に「成功・失敗をSlackに投げる」処理を入れて、週次で結果を通知するようにしています。失敗したら赤いメッセージがSlackに飛んでくるので、忘れた頃に気づけます。
まとめ:週次のMac掃除を自動化してサボる仕組みを作る
Macの掃除は、シェルスクリプト1本とlaunchdのplist1つで完全自動化できます。ポイントは3つに集約できます。
- 掃除対象を絞る:Homebrew・Xcode・Dockerの3つが容量インパクト最大
- launchdで時間帯を分散:日曜3〜5時に15分刻みで散らすと安全
- ログとSlack通知で静かな失敗を防ぐ:無人実行の最大リスクへの保険
私自身、この仕組みを作ってから1年以上、Macの容量問題で焦ったことがありません。しかも毎週のメンテ作業が0分になります。筋トレと違って、一度セットすれば意志力がいらないのが最大のメリット。
最初のplist書きだけちょっと面倒ですが、Weekday・Hour・Minuteを書き換えるだけなので、1回作れば使い回しが効きます。まずはbrew cleanup相当のミニマム版から始めて、慣れてきたらXcodeやDockerを足していく順番がおすすめです。
週末に30分だけ時間を作って、ぜひ試してみてください。