🐰

macOSで特定の外付けHDDをスリープさせないようにするスクリプト

2025/01/24に公開

どういうわけか、macOSで外付けHDDのスリープ制御をうまく設定できなくなりました。私の環境の問題なのか、最近のOSの仕様変更なのか調査しきれていません。pmsetコマンドでdisksleepの値を操作するなどの手も試しましたがうまくいかなかったため、手元で導入しているLaCie製HDDデバイスそのものの特性と、OSの仕様変更の両方を疑っています。

この問題をこれ以上追求することを諦め、別の方法でスリープを抑制する仕組みを考えてみました。私は「スリープさせたくないHDDに対して、プログラムが定期的にアクセスし続ければ良いのではないか?」と考え、一定期間ごとに空ファイルを書き込むスクリプトをLaunchAgentに登録する案を採用してみました。

LaunchAgentとは、launchdというサービスによって管理・実行されるプロセスの仕組みです。macOSで起動時(ログイン時)に何かを実行したり、cronやdaemonのようにプログラムを定期実行したりするためのものです。

任意のボリュームに対し、空ファイルを書き込むためのスクリプト

wakeupdrives.shと名付け、以下のようなシェルスクリプトを組みました。記事冒頭では「HDD」と言っていますが、スクリプトとしてHDD/SSDの区別は特に行っていません。

#!/bin/sh

## スリープ抑制の対象にしたいボリュームの名前(複数列挙可能)
volumeNames=("Alpha" "Beta")

## 空ファイルの名前
wakeupFileName=".wakeup"

## スクリプト動作のオン/オフ用ファイル
enablerFilePath="$HOME/WakeupDrives"

timestamp=`date '+%Y-%m-%d %H:%M:%S'`

## `~/WakeupDrives` が見つからない場合、スクリプトを終了
if [ ! -e $enablerFilePath ]; then
	echo "$timestamp: [STOP] exit wakeupdrives.sh because “~/WakeupDrives” file is not exist." # debug line
	exit 0
fi

for volumeName in ${volumeNames[@]}; do
	volumePath="/Volumes/$volumeName"
	if [ -e $volumePath ]; then
		#echo "$volumePath/$wakeupFileName" # debug line
		
		## "/Volumes/VOLUMENAME/.wakeup" に空ファイルを書き込む
		echo "" > $volumePath/$wakeupFileName
		echo "$timestamp: [OK] $volumePath/$wakeupFileName" # debug line
	fi
done

volumeNames

スリープ抑制の対象にしたいボリュームの名前を列挙します。Finderで見える名前をそのまま設定してください。例えば「Macintosh HD」のようなラベルです。

wakeupFileName

対象ボリュームのスリープを抑制するために書き込む空ファイルの名前を設定します。

enablerFilePath

$HOME/WakeupDrivesという空ファイルを置いておくと、このスクリプトが動作します。ファイルを移動させたり削除させたりすると、スクリプトを止めることができます。明示的なGUIが存在しないため、ファイルの存在性を電源スイッチ代わりにしています。

LaunchAgent用plist

LaunchAgentに登録するためのplistです。これを登録すると、対象のコマンドをmacOSのバックグラウンドで定期実行させることができます。plistファイルは ~/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>wakeupdrives</string>
	<key>Program</key>
	<string>/usr/local/bin/wakeupdrives.sh</string>
	<key>ProgramArguments</key>
	<array/>
	<key>StartInterval</key>
	<integer>25</integer>
	<key>RunAtLoad</key>
	<true/>
 	<key>StandardErrorPath</key>
 	<string>/Users/YOURHOME/agent_wakeupdrives_err.log</string>
 	<key>StandardOutPath</key>
 	<string>/Users/YOURHOME/agent_wakeupdrives_stdout.log</string>
</dict>
</plist>

要点のみ。

  • Program
    • 実行するコマンドのパス
  • StartInterval
    • 定期実行間隔(秒)
  • RunAtLoad
    • デスクトップ起動時(ログイン時)に実行するか
  • StandardErrorPath
    • stderrの出力先パス(上記のYOURHOMEをホームの名前に変えること)
  • StandardOutPath
    • stdoutの出力先パス(上記のYOURHOMEをホームの名前に変えること)

パラメータの詳しい資料:
https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html

LaunchAgentを登録する

launchctlでplistを登録してください。うまくいけばmacOSのログイン項目の設定に登録されます。

launchctl load ~/Library/LaunchAgents/wakeupdrives.plist

トラブルシュート

一度unloadしてから再度loadする

launchctl unload ~/Library/LaunchAgents/wakeupdrives.plist
launchctl load ~/Library/LaunchAgents/wakeupdrives.plist

plistの文法チェック

plutil -lint ~/Library/LaunchAgents/wakeupdrives.plist 

スクリプトファイルに実行権限を付与

chmod 664 /usr/local/bin/wakeupdrives.sh

StandardOutPathにprintして検証

スクリプトファイルが実行されているにもかかわらずうまく動かない場合は、StandardOutPathに出力して検証してみてください。

LaunchAgentがエラーを検知すると、StandardErrorPathの方にその内容が出力されるはずです。

Discussion