LaunchDaemon无法找到bash命令问题排查求助
问题:LaunchDaemon触发bash脚本时无法正确执行blueutil命令
场景说明
我在MacBook上编写了一个bash脚本,用来根据WF-1000XM3蓝牙耳机的连接状态自动启用/禁用睡眠,实现合盖听歌时不受干扰。脚本存放于/Users/klumpy/Library/Scripts目录,由LaunchDaemon每5秒触发一次,依赖brew安装的blueutil命令。
原脚本内容
#!/usr/bin/env export PATH=$(cat /Users/klumpy/Library/Scripts/PATH) export BLUEUTIL_ALLOW_ROOT=1 # Check if "WF-1000XM3 is connected, if yes disable sleep, if not, don't go to sleep. echo $(blueutil --connected) echo $(blueutil --connected | grep "WF-1000XM3") if [[ $(blueutil --connected | grep "WF-1000XM3" -c) -ne 0 ]]; then sudo pmset disablesleep 1 echo "Sleep Disabled" else sudo pmset disablesleep 0 echo "Sleep Enabled" fi
原LaunchDaemon 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.example.bluetoothsleep</string> <key>ProgramArguments</key> <array> <string>sudo</string> <string>bash</string> <string>/Users/klumpy/Library/Scripts/disablesleep</string> </array> <key>StandardErrorPath</key> <string>/Users/klumpy/Documents/Programming/bin/stderr.txt</string> <key>StandardOutPath</key> <string>/Users/klumpy/Documents/Programming/bin/stdout.txt</string> <key>StartInterval</key> <integer>5</integer> </dict> </plist>
问题现象
- 脚本在终端运行完全正常,但LaunchDaemon触发时找不到
blueutil命令; - 最初打印
$PATH仅得到/usr/bin:/bin:/usr/sbin:/sbin,将终端$PATH内容存入脚本同目录的PATH文件并导出后,脚本输出只剩“Sleep Enabled”,前两条echo无内容; - 无论耳机是否连接,脚本始终走else分支,完全无法识别耳机状态。
错误原因及修复方案
1. 修复脚本shebang错误
原脚本第一行#!/usr/bin/env不完整,未指定具体shell,LaunchDaemon可能默认用sh执行,导致语法和环境差异。修改为:
#!/usr/bin/env bash
2. 直接指定blueutil绝对路径,避免PATH问题
brew安装的blueutil路径分两种:
- Apple Silicon Mac:
/opt/homebrew/bin/blueutil - Intel Mac:
/usr/local/bin/blueutil
在脚本里直接用绝对路径调用,彻底规避PATH配置的坑:
# 根据自己的Mac架构选择路径 BLUEUTIL_PATH="/opt/homebrew/bin/blueutil" # BLUEUTIL_PATH="/usr/local/bin/blueutil"
3. 移除LaunchDaemon中的冗余sudo
LaunchDaemon本身以root身份运行,无需在ProgramArguments里加sudo——sudo会重置环境变量,导致之前配置的PATH失效。修改plist的ProgramArguments:
<key>ProgramArguments</key> <array> <string>/bin/bash</string> <string>/Users/klumpy/Library/Scripts/disablesleep</string> </array>
同时脚本里的sudo pmset也可以去掉sudo,root身份运行不需要额外授权。
4. 优化脚本逻辑,减少重复调用
原脚本重复执行blueutil --connected三次,既低效又可能导致状态不一致,改为先把结果存到变量里再复用:
connected_devices=$($BLUEUTIL_PATH --connected) echo "$connected_devices" echo "$connected_devices" | grep "WF-1000XM3" if echo "$connected_devices" | grep -q "WF-1000XM3"; then
修复后的完整脚本
#!/usr/bin/env bash # 根据Mac架构选择对应路径 BLUEUTIL_PATH="/opt/homebrew/bin/blueutil" # BLUEUTIL_PATH="/usr/local/bin/blueutil" export BLUEUTIL_ALLOW_ROOT=1 connected_devices=$($BLUEUTIL_PATH --connected) echo "$connected_devices" echo "$connected_devices" | grep "WF-1000XM3" if echo "$connected_devices" | grep -q "WF-1000XM3"; then pmset disablesleep 1 echo "Sleep Disabled" else pmset disablesleep 0 echo "Sleep Enabled" fi
修复后的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.example.bluetoothsleep</string> <key>ProgramArguments</key> <array> <string>/bin/bash</string> <string>/Users/klumpy/Library/Scripts/disablesleep</string> </array> <key>StandardErrorPath</key> <string>/Users/klumpy/Documents/Programming/bin/stderr.txt</string> <key>StandardOutPath</key> <string>/Users/klumpy/Documents/Programming/bin/stdout.txt</string> <key>StartInterval</key> <integer>5</integer> </dict> </plist>
内容的提问来源于stack exchange,提问作者Klumpy7
相关产品推荐
相关产品推荐

