launchctl 是 macOS 管理 launchd 服务的唯一可靠接口;查状态用 launchctl list 和 launchctl print,启停自启用 enable/disable,重载需 bootout 后 load,start/stop 并非总生效。

launchctl 是 macOS 管理 launchd 服务的唯一可靠接口,直接操作 plist 文件或用 GUI 工具无法真正控制服务生命周期——所有“看似生效”的操作,最终都得走 launchctl。
怎么查一个服务当前是否在运行
别依赖 Activity Monitor 或 ps aux | grep,那些只看进程,不反映 launchd 的真实状态。正确做法是用 launchctl list 查服务注册状态,再结合 launchctl print 看详细运行时信息:
-
launchctl list | grep com.example.service—— 只显示已加载的服务(第三列是 exit code,0 表示最近正常退出,非 0 或 - 表示仍在运行或异常) -
launchctl print gui/501/com.example.service—— 替换501为你的用户 UID(id -u查),gui表示用户级服务;输出中state = running才算真正在跑 - 如果
list里没有,说明服务根本没加载,不是“没启动”,而是“不存在于 launchd 管理范围”
怎么启用/禁用开机自启(不是启动/停止服务)
很多人混淆“启用自启”和“立即启动”。launchctl enable 和 disable 控制的是服务的“自动加载策略”,不影响当前运行状态:
-
launchctl enable gui/501/com.example.service—— 下次登录时自动加载并按 plist 中的RunAtLoad或KeepAlive决定是否启动 -
launchctl disable gui/501/com.example.service—— 即使 plist 有RunAtLoad = true,登录时也不会加载它 - 注意:系统级服务用
system替代gui/501,但修改 system 级 plist 需要sudo,且 macOS 12+ 对 /System/Library/LaunchDaemons 有 SIP 保护,普通用户无法修改
怎么安全地重载一个已修改的 plist 文件
改完 .plist 后不能只靠 launchctl start,必须先卸载再重新加载,否则旧配置仍驻留在 launchd 中:
-
launchctl bootout gui/501/com.example.service—— 强制终止并卸载(比unload更彻底,会清理 socket、xpc 等关联资源) -
launchctl load /Users/you/Library/LaunchAgents/com.example.service.plist—— 重新加载(路径必须绝对,不能用~) - 如果报错
Could not find specified service,大概率是 plist 文件名和Label字段不一致,launchd 只认Label,文件名只是约定 - 加载后不会自动 start,除非 plist 里明确写了
RunAtLoad = true或触发条件已满足(如文件监听、定时器到期)
为什么 launchctl start/stop 经常没反应
因为 start 和 stop 不是万能开关,它们只对“支持手动触发”的服务有效。很多服务被设计为仅响应事件(比如监听端口、文件变化),launchctl start 调用后立刻退出,根本不会驻留进程:
-
launchctl start gui/501/com.example.service成功返回 ≠ 服务在运行,得用print确认 state - 如果服务定义了
KeepAlive = false且无其他触发器,start启动后执行完就退出,launchd 不会重启它 - 某些服务(如基于
inetd模式或Sockets的)根本不响应start,只能靠触发对应 socket 或 path 才会拉起 - 调试时优先用
launchctl kickstart -k gui/501/com.example.service强制重启一次,比反复stop/start更可靠
真正难的不是命令怎么敲,而是理解每个命令背后对应的是 launchd 的哪个子系统(job registry、service state、activation trigger)。改完 plist 忘记 bootout,或者把 enable 当成 start 用,是 macOS 上最隐蔽也最常复现的问题根源。

















