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