932 字
5 分钟
Mac Mini 定时关屏:从 crontab 踩坑到 LaunchDaemon

睡前想让 Mac Mini 自动把屏幕关了。听起来就一行 crontab 的事,结果踩了三个坑,最后换成了 LaunchDaemon。

需求很简单#

Mac Mini 作为 always-on 的服务器跑着,平时 displaysleep 设成 0(永不休眠),因为远程操作时不希望屏幕乱睡。但晚上没人看,屏幕亮一夜纯属浪费。

需求:每天 00:00 自动关闭显示器,其他时间不管。

第一反应:crontab#

SSH 上去,一行搞定:

Terminal window
echo '0 0 * * * /usr/bin/pmset displaysleepnow' | crontab -

pmset displaysleepnow 是 macOS 提供的命令,立即让显示器进入睡眠,但不影响系统本身——机器照常跑,SSH 照常连。

看起来完美。但实际上这个方案根本跑不通

坑一:pmset 需要 root 权限#

pmset displaysleepnow 不是随便哪个用户都能调的,它需要 root 权限。用户级的 crontab 执行这条命令,直接被拒:

Operation not permitted

要让 crontab 能跑,要么配 sudoers 的 NOPASSWD 规则,要么用 sudo crontab -e 编辑 root 的 crontab。两种都不优雅。

坑二:macOS 的 cron 需要 Full Disk Access#

从 macOS Mojave 开始,苹果给 cron 加了权限限制。/usr/sbin/cron 必须在 系统设置 → 隐私与安全 → 完全磁盘访问权限 里被授权,否则 cron job 会静默失败——不报错,就是不执行。

这个坑尤其恶心,因为你完全不知道它没跑,日志里也没什么有用信息。

坑三:Mac 睡着了 cron 不会补执行#

如果 00:00 的时候 Mac 恰好处于睡眠状态(虽然我的 Mini 设了 sleep 0,但万一呢),cron 不会在唤醒后补跑错过的任务。错过就是错过了。

正解:LaunchDaemon#

苹果从 2005 年就开始推 launchd 替代 cron,到现在 cron 基本算是”还能用但没人管”的状态。LaunchDaemon 才是 macOS 上定时任务的正道:

  • 以 root 身份运行,不需要 sudo 配置
  • 支持错过补执行,如果触发时机器在睡觉,醒来后会补上
  • 不需要 Full Disk Access 这种额外权限配置
  • Apple 官方推荐,和系统集成更好

创建 plist 文件 /Library/LaunchDaemons/com.local.displaysleepnow.plist

/Library/LaunchDaemons/com.local.displaysleepnow.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>com.local.displaysleepnow</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/pmset</string>
<string>displaysleepnow</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>0</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
</dict>
</plist>

几个关键点:

  • Label 是这个 daemon 的唯一标识,随便起,但要有辨识度
  • ProgramArguments 用数组形式传命令和参数,不要写成一整个字符串
  • StartCalendarInterval 指定触发时间,格式类似 crontab 但用 dict 表示。只写 HourMinute 意味着每天都触发

安装和加载:

Terminal window
sudo cp com.local.displaysleepnow.plist /Library/LaunchDaemons/
sudo chown root:wheel /Library/LaunchDaemons/com.local.displaysleepnow.plist
sudo chmod 644 /Library/LaunchDaemons/com.local.displaysleepnow.plist
sudo launchctl load /Library/LaunchDaemons/com.local.displaysleepnow.plist

权限必须是 root:wheel + 644,否则 launchctl 会拒绝加载,报 “Path had bad ownership/permissions” 之类的错。

验证文件就位:

Terminal window
ls -la /Library/LaunchDaemons/com.local.displaysleepnow.plist
-rw-r--r-- 1 root wheel 562 Apr 1 13:56 com.local.displaysleepnow.plist

LaunchDaemon vs LaunchAgent#

macOS 的 launchd 有两种配置:

类型位置运行身份适用场景
LaunchDaemon/Library/LaunchDaemons/root系统级任务,需要高权限
LaunchAgent~/Library/LaunchAgents/当前用户用户级任务,不需要 sudo

pmset displaysleepnow 需要 root,所以必须用 LaunchDaemon。如果你的定时任务不需要特殊权限(比如跑个备份脚本),LaunchAgent 就够了。

displaysleepnow vs sleepnow#

别搞混这两个:

  • pmset displaysleepnow —— 只关显示器,系统正常运行,SSH/远程连接不受影响
  • pmset sleepnow —— 整台机器睡眠,除非开了 Wake on LAN,否则远程连不上

对于当服务器用的 Mac Mini,肯定选前者。

如果想卸载#

Terminal window
sudo launchctl unload /Library/LaunchDaemons/com.local.displaysleepnow.plist
sudo rm /Library/LaunchDaemons/com.local.displaysleepnow.plist

先 unload 再删文件,顺序不能反。

小结#

一个”每天零点关屏”的需求,crontab 方案看着一行搞定,实际上权限、FDA 授权、补执行三个坑等着你。macOS 上做定时任务,直接上 LaunchDaemon/LaunchAgent,省心。

Mac Mini 定时关屏:从 crontab 踩坑到 LaunchDaemon
https://blog.lishuyu.top/posts/macos定时关屏/
作者
猫猫魔女
发布于
2026-04-01
许可协议
CC BY-NC-SA 4.0