脚本移至其他目录后Cronjob执行失败问题排查
问题原因分析及解决方案
问题背景
脚本包含以下bash特有语法:
readarray users < <(cat /etc/passwd | grep 'aText' | awk -F':' '{print $1}');
- 脚本在主目录下手动运行、sudo运行、通过
sudo crontab -e配置的Cron任务均正常执行 - 移至
/opt/my-org/my-app/utils/myscript.sh后,手动运行正常,但Cron任务报错,日志内容:
/opt/my-org/my-app/utils/myscript.sh: line 6: syntax error near unexpected token `<' /opt/my-org/my-app/utils/myscript.sh: line 6: `readarray users < <(cat /etc/passwd | grep 'aText' | awk -F':' '{print $1}');'
- 环境:RHEL 7.9,脚本已声明
#!/bin/bash,bash版本4.3 - 额外测试现象:
$ readarray users < <(cat /etc/passwd | grep 'aText' | awk -F':' '{print $1}'); $ echo $? 0 $ sudo readarray users < <(cat /etc/passwd | grep 'aText' | awk -F':' '{print $1}'); sudo: readarray: command not found $ echo $? 1
核心原因
Cron默认Shell限制:
Cron的默认执行Shell是/bin/sh,RHEL 7中/bin/sh是bash的POSIX兼容模式,该模式下会禁用readarray、进程替换< <()等bash特有语法。即使脚本声明了#!/bin/bash,若Cron环境强制使用/bin/sh解释脚本,就会触发语法错误。
脚本在主目录时Cron正常,是因为主目录的执行环境意外继承了bash配置;移至/opt后,Cron触发了默认的POSIX模式解释逻辑。sudo直接执行内置命令的问题:
readarray是bash内置命令,而非系统PATH中的外部程序。sudo readarray会尝试在PATH中查找该命令,自然找不到;但脚本中是通过bash解释执行,所以手动运行正常。
解决方案
方案1:强制Cron使用bash
在sudo crontab -e的开头添加一行,指定Shell为bash:
SHELL=/bin/bash */15 * * * * /opt/my-org/my-app/utils/myscript.sh > /opt/my-org/my-app/utils/myscript.log 2>&1
方案2:Cron命令中显式调用bash执行脚本
修改Cron任务为:
*/15 * * * * /bin/bash /opt/my-org/my-app/utils/myscript.sh > /opt/my-org/my-app/utils/myscript.log 2>&1
方案3:优化脚本语法,兼容POSIX Shell
将bash特有语法替换为POSIX兼容写法,避免依赖bash特性:
# 替换原readarray语句 users=() # 用awk直接过滤,减少管道 awk -F':' '/aText/ {print $1}' /etc/passwd | while IFS= read -r user; do users+=("$user") done
内容的提问来源于stack exchange,提问作者Edgar Zamora
相关产品推荐
相关产品推荐

