输入脚本名称时,它运行得很完美。放进 crontab 定时之后,却什么也没发生:没有备份文件,没有邮件,也没有错误。Cron 任务不运行,是 Linux 管理中最常见的小难题之一,而原因几乎从来不在 cron 本身。问题出在您的交互式 shell 与 cron 给每个任务的那个空白环境之间的差异。这里按值得检查的顺序列出常见原因,以及如何构建真正值得信赖的定时任务。
1. Cron 任务不运行?先从环境入手
Cron 以最精简的环境启动任务。它不会读取 .bashrc 或 .profile,默认的 cron PATH 只有 /usr/bin:/bin。位于 /usr/local/bin 或 /usr/sbin 的命令,或只为您的用户安装的工具,就是找不到。Cron 环境变量同样只有一小串:您在配置文件中导出的数据库密码、代理设置,或您在交互使用时依赖的语言设置,都不会存在。
解决办法:在脚本中对命令使用完整路径,在 crontab 或脚本顶部设置 PATH,并从脚本明确读取的文件中加载任务需要的任何配置。要确切了解 cron 提供了什么,可以安排一次性任务,把 env 的输出写入 /tmp 中的文件,再与您自己的 shell 对比。
2. 任务在 sh 而不是 Bash 下运行
除非 crontab 设置了 SHELL,否则 cron 用 /bin/sh 运行每条命令行。在 Debian 和 Ubuntu 上,它是 dash,一个更小的 shell,不理解数组、双括号测试或 source 命令等 Bash 特性。请让每个脚本以 #!/bin/bash 行开头,设为可执行,并从 cron 调用脚本,而不是把冗长的 Bash 单行命令粘贴进 crontab。
3. 因文件本身导致 crontab 不工作
- 百分号。在 crontab 命令行中,cron 会把未转义的百分号变成换行。内联传给 date 命令的日期格式是典型的受害者。请用反斜杠转义每一个,或者把命令移到脚本中。
- 最后一行。crontab 的最后一个条目之后需要一个换行,否则该条目可能被忽略。
- 用户字段。/etc/crontab 和 /etc/cron.d 中的条目在时间表与命令之间包含一个用户名;用 crontab -e 编辑的个人 crontab 则没有。把两种格式弄混,条目就会失效。
- cron 目录中的文件名。在基于 Debian 的系统上,/etc/cron.daily 及类似文件夹中的脚本由 run-parts 启动,它会跳过文件名中带点的文件。放在那里的名为 backup.sh 的脚本永远不会运行;请改名为 backup。/etc/cron.d 中的文件遵循同样的命名规则。
- 权限。这些文件夹中的脚本必须可执行,而属于某个用户的脚本,可能无法被任务所用的账户读取。
4. 它运行了,只是不在您预期的时间
Cron 遵循服务器的时区。许多云服务器运行在 UTC 上,所以原本要在洛杉矶(Los Angeles)凌晨 2 点运行的任务,实际上在太平洋时间的傍晚触发,而且夏令时开始或结束时,这个差距会移动一小时。用 timedatectl 检查该设置,然后要么按服务器的时区编写计划,要么有意识地更改时区。对于与营业时间挂钩的任务,请在条目旁边用注释注明时区。
5. 它运行了却静默失败:在哪里找 cron 日志
默认情况下,cron 会把任务的输出用电子邮件发给其所有者,在没有邮件投递的服务器上,这些邮件会石沉大海。在当前的 Debian 和 Ubuntu 上,cron 服务会把它启动的每个任务记录到 systemd 日志中,所以 journalctl -u cron 能显示任务是否被启动过。Debian 12 及更高版本默认不再安装 rsyslog,这就是您去找 cron 日志时 /var/log/syslog 可能不存在的原因。如果任务已启动但没有产生有用的输出,请把输出重定向到日志文件,或把 MAILTO 设为有人会读的地址,并让脚本自己报告失败。
让定时任务值得信赖
任务一旦运行起来,几个好习惯能让它持续运行。它们正是区分可以放心遗忘的定制 shell 脚本和悄悄失败数月的脚本的关键,也是我们所做的 Bash 脚本与自动化工作背后的规则:
- 严格模式。set -euo pipefail 让脚本在第一条命令失败时就停止,而不是带着缺失的数据继续运行。
- 不重叠运行。用带锁文件的 flock -n 包裹任务,意味着运行缓慢时,下一次启动会被跳过,而不是重复运行。
- 心跳。任务结束时向监控检查报告成功;如果报告没有到达,就会有人收到警报。
- 较重的任务使用 systemd 定时器。Systemd 定时器会记录到日志,可以通过 Persistent=true 补上服务器关机期间错过的运行,并在 systemctl list-timers 中显示上次和下次运行。
常见问题:Cron 任务不运行
如何不等计划时间就测试 cron 任务?
在同样空白的环境下运行它:用 env -i 加上精简的 PATH,以同一个用户的身份,并且如果 cron 使用 /bin/sh,就通过 /bin/sh 运行。如果这样能成功,从 cron 运行也会成功。在短时间内把它设为每分钟运行一次并观察日志,也行得通。
我的 cron 任务为什么运行了两次?
通常是因为它被安排在两个地方,例如个人 crontab 和 /etc/cron.d,或者因为下一次启动时上一次运行还没结束。请检查每个用户的 crontab -l,以及 /etc/crontab 和 /etc/cron.d,并用 flock 加锁。
为什么我的任务用 crontab -e 能运行,放到 /etc/cron.d 却不行?
几乎总是用户字段或文件名的问题。/etc/cron.d 中的条目需要用户列,而文件名中带点的文件会被忽略。
厌倦了只有人盯着才能工作的脚本?我们的定制 Bash 脚本与自动化服务会为备份、部署和健康检查编写、测试并记录定时任务,我们的 Bash 脚本服务也包括修复别人写的脚本。如需洛杉矶和长滩(Long Beach)的 Linux 自动化服务,请联系我们,简要描述任务及其运行的服务器。




