Shell脚本手动运行正常,通过Launch Agent执行失败求助
登录自动清空目录脚本异常问题解决
问题描述
编写了登录时自动执行的zsh脚本,用于清空Desktop、Documents和Downloads文件夹内容。手动运行脚本时所有目录正常清空,但通过Launch Agent触发执行时,stderr报错no matches found: /Users/jdoe/Desktop/*,仅输出“Checking /Users/jdoe/Desktop”后便停止,其余目录未处理。
相关代码与配置
原Shell脚本
#!/bin/zsh # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Removes files from the specified directories # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Define Variables userName="jdoe" directories=("Desktop" "Documents" "Downloads") # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Define functions removeFiles() { local folder="/Users/$userName/$dir" for file in "$folder"/* do echo "Removing $file" /bin/rm -rf "$file" done } clearFiles() { date for dir in "${directories[@]}" do echo "Checking folder $dir" removeFiles done } # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # main clearFiles exit 0
Launch Agent配置(两种尝试)
配置一
<?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>domain.label</string> <key>Program</key> <string>/bin/zsh</string> <key>ProgramArguments</key> <array> <string>/PATH/TO/script.sh</string> </array> <key>RunAtLoad</key> <true/> <key>StandardErrorPath</key> <string>/PATH/TO/domain.label.filename.stderr</string> <key>StandardOutPath</key> <string>/PATH/TO/domain.label.filename.stdout</string> </dict> </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>domain.label</string> <key>ProgramArguments</key> <array> <string>/PATH/TO/script.sh</string> </array> <key>RunAtLoad</key> <true/> <key>StandardErrorPath</key> <string>/PATH/TO/domain.label.filename.stderr</string> <key>StandardOutPath</key> <string>/PATH/TO/domain.label.filename.stdout</string> </dict> </plist>
权限设置脚本
setScriptPermissions() { chown jdoe ${script} chmod 755 ${script} }
setAgentPermissions() { chown jdoe "$plist" chmod 644 "$plist" }
问题原因
zsh在非交互式模式(Launch Agent触发的执行属于此模式)下默认启用nomatch选项:当通配符(如$folder/*)未匹配到任何文件时,会直接抛出错误并终止脚本执行。而手动运行脚本时处于交互式shell环境,该选项通常被禁用或有容错处理,因此不会触发错误。
解决方案
方案1:关闭zsh的nomatch选项
在脚本开头的#!/bin/zsh下方添加一行,关闭nomatch选项:
#!/bin/zsh setopt +o nomatch # 关闭nomatch,避免通配符无匹配时报错终止
修改后,即使目录为空,$folder/*会被当作普通字符串传递给rm -rf,而rm -rf处理不存在的路径不会报错,脚本会继续执行后续目录的清理。
方案2:改用find命令替代通配符循环
替换removeFiles函数,使用find命令直接删除目录内所有内容,彻底避免通配符问题:
removeFiles() { local folder="/Users/$userName/$dir" # 先检查目录是否存在 if [ -d "$folder" ]; then echo "Clearing contents of $folder" # 删除目录下所有内容(不删除目录本身) find "$folder" -mindepth 1 -delete fi }
find命令的-mindepth 1确保只处理目录内的内容,不会删除目录本身;-delete直接删除匹配项,无需循环处理。
优化Launch Agent配置
确保ProgramArguments的格式正确:如果指定解释器执行脚本,数组第一个元素应为解释器路径,第二个为脚本路径;若脚本本身有可执行权限且开头指定了#!/bin/zsh,直接设置脚本路径即可。推荐使用以下配置:
<key>ProgramArguments</key> <array> <string>/bin/zsh</string> <string>/PATH/TO/script.sh</string> </array>
验证步骤
- 应用上述修改后,重新加载Launch Agent:
launchctl unload /Users/jdoe/Library/LaunchAgents/domain.label.plist launchctl load /Users/jdoe/Library/LaunchAgents/domain.label.plist - 注销并重新登录,检查目标目录是否被清空,同时查看日志文件确认无报错。
内容的提问来源于stack exchange,提问作者user22547243
相关产品推荐
相关产品推荐

