macOSで特定の外付けHDDをスリープさせないようにするスクリプト
どういうわけか、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
をホームの名前に変えること)
- stderrの出力先パス(上記の
- StandardOutPath
- stdoutの出力先パス(上記の
YOURHOME
をホームの名前に変えること)
- stdoutの出力先パス(上記の
パラメータの詳しい資料:
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