当我的用户登录我的OS X计算机时,我正在尝试运行grunt watch
,因此我不必每次都手动在$ APP_ROOT目录中运行grunt watch
。
我在org.grunt.watch.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>org.grunt.watch</string>
<key>RunAtLoad</key>
<true/>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/grunt-watch-launchd</string>
</array>
</dict>
</plist>
/usr/local/bin/grunt-watch-launchd
是我创建的shell脚本:
#!/bin/sh
APP_ROOT=/path/to/htdocs/app
/usr/local/bin/daemon -- /usr/local/bin/grunt watch --gruntfile="$APP_ROOT"/Gruntfile.js > /tmp/grunt-watch-launchd.log 2>&1
该脚本应使用daemon
实用程序(随brew install daemon
安装)和&#34; daemonize&#34; grunt watch
命令反过来加载Gruntfile.js
配置并启动监视任务。
当我与用户手动运行CLI中的/usr/local/bin/grunt-watch-launchd
时,一切正常。我看到daemon
ps aux | grep grunt
运行grunt watch
命令。如果我在APP_ROOT
内编辑文件,Grunt的watch
任务会触发Gruntfile.js
内的特定任务。
但问题是,当我与用户登录时,我希望launchd
自动启动/usr/local/bin/grunt-watch-launchd
。问题是当我运行launchctl
:
launchctl load /Library/LaunchAgents/org.grunt.watch.plist
未加载服务。或者至少,launchd
调用脚本(因为我看到文件/tmp/grunt-watch-launchd.log
已创建,因此脚本运行,尽管/tmp/grunt-watch-launchd.log
为空),但似乎没有创建守护程序进程或以某种方式被launchd
杀死。
此外,/var/log/system.log
内没有任何内容。如果我尝试使用sudo运行launchctl
:
sudo launchctl unload /Library/LaunchAgents/org.grunt.watch.plist && sudo launchctl load /Library/LaunchAgents/org.grunt.watch.plist
/tmp/grunt-watch-launchd.log
将包含以下行:
daemon: fatal: refusing to execute unsafe program: /usr/local/bin/grunt (/usr/local/lib is group writable)
使用sudo,/var/log/system.log
告诉我:
Jun 11 18:22:24 antons-mbp com.apple.xpc.launchd[1] (org.grunt.watch[83009]): Service exited with abnormal code: 1
无论哪种方式(launchctl
有和没有sudo),我都可以确认服务没有启动:
mymachine:~ user$ launchctl list | grep grunt
- 0 org.grunt.watch
当我的用户登录时,运行此脚本作为守护程序的正确方法是什么?
感谢您的关注。
编辑:
我忘了说我使用Mac OS X 10.12 Sierra,用npm
安装了Grunt,我使用的是MacBook Pro(13英寸,2012年中)(如果这可能有帮助)。
编辑2:
我发现了这个问题。当作为launchd
代理运行时,脚本无法找到命令,因为代理的用户不是我的用户。因此发生了127错误。
所以这对于像我这样坚持一个非常简单的launchd
代理人的所有人来说:
始终检查您使用的命令是否在启动命令的用户的PATH中。使用绝对路径,如有必要,在脚本的第一行设置PATH变量。
将所有命令输出重定向到文件,以便在launchd
启动脚本时查看是否发生错误(在我的情况下,错误没有显示在/var/log/system.log
中出于某种原因)。
答案 0 :(得分:1)
我不熟悉grunt
或daemon
实用程序,但我非常确定daemon
与launchd管理作业的方式相冲突。从本质上讲,您使用两种不同的守护程序创建工具来执行不同的操作,而您只需选择一种。
更具体地说,我怀疑daemon
正在后台启动grunt
(即守护它)。但是,launchd希望它所管理的工作保持在可以监控和控制它们的前台。可能发生的事情是launchd启动你的脚本,脚本在后台运行grunt watch
然后退出...并且launchd看到作业已经退出并帮助清理剩余的子进程,如{{1} }。结果:没有实际的grunt
守护程序正在运行。
您可以将grunt
添加到.plist中,告诉launchd不要杀掉后台进程,但实际上最好以启动方式执行操作并将<key>AbandonProcessGroup</key><true/>
留在前台。因此,要么从您的脚本中删除grunt
命令,要么将其替换为daemon
,它将作为launchd下的顶级进程运行exec
(正常运行它会使其成为shell的子进程,并将shell保留为launchd下的顶级进程。
这里可能还有其他问题,但在修复此问题之前很难说清楚。