crontab 命令详解与参数实测(Ubuntu 22.04)

基于 Ubuntu 22.04(cron 3.0pl1-137ubuntu3)逐参数实测 crontab:无参数 replace 高危行为、-l 与 no crontab 报错、标准输入与文件安装、五字段格式(列表/范围/步进)、@hourly/@daily/@reboot 简写、spool 落盘与 600 权限、-u 多用户与特权校验、-r/-ri 删除、非法字段报错、65 秒真实执行实证与 syslog 日志核对、% 转义陷阱。

Linux命令Linux系统UbuntuUbuntu 22.04命令行进程管理2026/10/16

crontab 命令详解与参数实测(Ubuntu 22.04)

目标:全面掌握 crontab 的每一个常用参数——无参数 replace 的高危行为、-l 列出与 no crontab 报错、标准输入与文件两种安装方式、五字段时间格式(列表/范围/步进/星号)逐字段解读、@hourly/@daily/@reboot 等简写、/var/spool/cron/crontabs/ 落盘位置与 600 权限、-u 多用户操作与特权校验、-r/-ri 删除与交互确认、非法字段报错形态,以及「等 65 秒」的真实执行实证与 syslog 日志核对,全部命令与回显已在 Ubuntu 22.04(cron 3.0pl1-137ubuntu3)实测通过。

一、环境信息

本文所有命令与回显均在以下环境实测采集,读者在相同版本的 Ubuntu 上可直接复现:

项目实测值
操作系统Ubuntu 22.04.5 LTS
架构x86_64
cron 包版本3.0pl1-137ubuntu3(crontab 是其中的一员)
cron 守护进程/usr/sbin/cron(service cron 管理运行状态)
用户 crontab 落盘目录/var/spool/cron/crontabs/
系统级 crontab/etc/crontab、/etc/cron.d/
日志载体/var/log/syslog(由 rsyslog 落盘)
演示目录/root/demo/crontab

环境确认命令与实测回显如下:

$ head -2 /etc/os-release
PRETTY_NAME="Ubuntu 22.04.5 LTS"
NAME="Ubuntu"

$ uname -m
x86_64

$ dpkg -l cron | tail -1
ii  cron  3.0pl1-137ubuntu3  amd64  process scheduling daemon

$ service cron status
 * cron is running

💡 说明:crontab 只是「管理定时任务表的工具」,真正到点执行任务的是 cron 守护进程。所以用 crontab 之前先确认 cron 服务在跑(service cron status 或 systemctl status cron),crontab 装了任务而 cron 没跑,是最常见的「任务不执行」原因。

二、命令概览

2.1 语法与测试数据

crontab [-u user] file
crontab [ -u user ] [ -i ] { -e | -l | -r }

参数结构解读:

  • file:安装文件作为新的 crontab;file 位置写 - 表示从标准输入读;
  • -l:列出当前(或 -u 指定的)用户的 crontab;
  • -r:删除 crontab;-i 与 -r 连用,删除前询问确认;
  • -e:调用编辑器编辑(本文以「文件/标准输入安装」为主线,-e 依赖交互终端,行为等价于编辑后重装);
  • -u user:指定目标用户,仅 root 可用。

crontab 任务行的时间部分是五个字段,后面跟要执行的命令:

┌───────── 分钟 (0-59)
│ ┌───────── 小时 (0-23)
│ │ ┌───────── 日 (1-31)
│ │ │ ┌───────── 月 (1-12)
│ │ │ │ ┌───────── 周 (0-7,0 与 7 都是周日)
│ │ │ │ │
* * * * *  要执行的命令

字段取值支持四种写法(3.3 节逐个实测):星号 *(任意)、列表 1,15、范围 9-18、步进 */10。

测试环境准备(演示目录、演示用户 tester、cron 与 syslog 状态):

$ mkdir -p /root/demo/crontab

$ useradd -m -s /bin/bash tester

$ id tester
uid=1012(tester) gid=1016(tester) groups=1016(tester)

$ service cron status
 * cron is running

$ ps -ef | grep [r]syslog | head -2
syslog     21939       1  0 23:50 ?        00:00:00 rsyslogd

💡 说明:syslog 守护进程(rsyslog)负责把 cron 的执行日志落到 /var/log/syslog;最小化安装的系统可能没有它,补装与启动方法见 4.4 节。

2.2 用法提示全量输出(逐行照抄)

crontab 没有 --help;给一个非法选项即可触发完整用法提示:

$ crontab -Z; echo rc=$?
crontab: invalid option -- 'Z'
crontab: usage error: unrecognized option
usage:	crontab [-u user] file
	crontab [ -u user ] [ -i ] { -e | -l | -r }
		(default operation is replace, per 1003.2)
	-e	(edit user's crontab)
	-l	(list user's crontab)
	-r	(delete user's crontab)
	-i	(prompt before deleting user's crontab)
rc=1

💡 要点:括号里那句 (default operation is replace, per 1003.2) 是全篇最重要的警告——不带 -e/-l/-r 时,crontab 的默认动作是「用输入替换现有任务表」,无参数执行会把 stdin(往往是空/立即 EOF)装成新的空 crontab。实测见 3.1 节,建议先读完 3.1 再上手。

2.3 版本信息

crontab 属于 cron 包,版本用 dpkg 查询(见第一章,实测 3.0pl1-137ubuntu3)。另一个版本证据在落盘文件的头注释里(3.6 节实测原文):# (Cron version -- $Id: crontab.c,v 2.13 1994/01/17 03:20:37 vixie Exp $)——Ubuntu 的 cron 是 Vixie cron 的 Debian 衍生版。

三、参数逐项实测

3.1 无参数:默认 replace 的高危行为

裸敲 crontab 会发生什么?实测(执行前 root 无 crontab,stdin 立即 EOF):

$ crontab; echo rc=$?
rc=0

$ crontab -l; echo rc=$?
rc=0

解读:无参数的 crontab 走默认 replace 分支,从 stdin 读入任务表;stdin 立即 EOF → 安装了一张空表,退出码 0、无任何提示。之后 crontab -l 静默返回空内容(rc=0)——空表是「存在但为空」,与「没有 crontab」是两种状态(对比 3.2 节)。

⚠️ 注意:如果执行裸 crontab 之前你已有一张任务表,它会被这张空表整体替换,且无确认、无提示。这是 crontab 最著名的删除事故来源。规避方式:永远不裸敲 crontab;要清空任务表用 crontab -r(3.8 节),并用 4.2 节的「先备份再改」流程兜底。

💡 要点:无参数 crontab 的实际用途是「从文件/管道安装任务表」——crontab 任务文件 或 生成命令 | crontab - 是脚本化管理定时的正路(4.1 节实测)。它默认 replace 的语义意味着:任何安装动作都是整表替换而非追加,追加式修改必须「先 crontab -l 取旧表 → 拼接 → 再整表装回」。

3.2 -l:列出 crontab 与 no crontab 报错

没有 crontab 时 -l 的真实报错形态(退出码 1):

$ crontab -l; echo rc=$?
no crontab for root
rc=1

💡 要点:no crontab for root 走 stderr 且退出码为 1;脚本里判断「有没有定时任务」应该用退出码而不是匹配文本。-l 列出已存在内容时 rc=0(3.3 节起各示例可见)。

3.3 标准输入安装(| crontab -)与五字段格式

最常用的安装方式:把任务表文本通过管道喂给 crontab -。先装一条最简单的任务(每分钟写一次时间戳到文件,供 3.11 节执行实证用):

$ echo '*/1 * * * * date > /root/demo/crontab/ran.txt' | crontab -; echo rc=$?
rc=0

$ crontab -l
*/1 * * * * date > /root/demo/crontab/ran.txt

五种字段写法一次装齐(列表、范围、步进、星号组合),实测安装与回读:

$ crontab /root/demo/crontab/five-fields.txt; echo rc=$?
rc=0

$ crontab -l
*/1 * * * * date > /root/demo/crontab/ran.txt
0 2 * * * echo daily-at-0200
30 4 1,15 * * echo on-1st-and-15th
0 9-18 * * 1-5 echo workhours
*/10 8-18 * * * echo every-10min-in-8-18

对照上面五条任务行,逐字段解读五字段格式:

字段含义合法值写法与实测示例
第 1 列 分钟每小时的第几分钟0-590(整点)、30;*/1 每分钟、*/10 每 10 分钟
第 2 列 小时每天的第几小时0-232(凌晨 2 点)、8-18 范围(8 点到 18 点每小时)
第 3 列 日每月第几天1-311,15 列表(每月 1 号和 15 号)、* 任意日
第 4 列 月每年第几月1-12* 任意月
第 5 列 周每周第几天0-7(0 和 7 都是周日)1-5 范围(周一到周五)
之后要执行的命令shell 命令echo workhours、date > /root/demo/crontab/ran.txt

组合语义对照:0 2 * * * 每天 02:00;30 4 1,15 * * 每月 1 号、15 号的 04:30;0 9-18 * * 1-5 工作日(周一至周五)9 点到 18 点的每个整点;*/10 8-18 * * * 每天 8:00-18:59 间每 10 分钟一次。

💡 要点一:日、周两列同时不是 * 时是「或」的关系(如 30 4 1 * 1 = 每月 1 号或每周一的 04:30 都会跑),这是 cron 的历史语义,容易想当然成「且」。

💡 要点二:任务行支持注释(# 开头)与 变量=值 环境变量行,实测写入后原样保存(4.2 节含 PATH= 行的实测)。

3.4 文件安装(crontab file)

除了标准输入,还可以直接安装一个文件。文件内容与 -l 回显完全一致:

$ crontab /root/demo/crontab/special.txt; echo rc=$?
rc=0

$ crontab -l
@hourly echo hourly-run >> /root/demo/crontab/hourly.log
@reboot echo reboot-run >> /root/demo/crontab/reboot.log
@daily echo daily-run

💡 要点:crontab 文件名 与 crontab 文件名 < 输入 是同一动作的两种来源;文件安装常用于批量迁移(把旧机器的 crontab -l > /root/demo/crontab/backup.txt 导出,在新机器 crontab /root/demo/crontab/backup.txt 装回,完整流程见 4.2 节)。

3.5 特殊简写:@hourly、@daily、@reboot 等

五字段太啰嗦时可以用 @ 简写替代整个时间部分(写入后 -l 原样展示,不会被展开):

$ crontab /root/demo/crontab/special.txt; echo rc=$?
rc=0

$ crontab -l
@hourly echo hourly-run >> /root/demo/crontab/hourly.log
@reboot echo reboot-run >> /root/demo/crontab/reboot.log
@daily echo daily-run

常用简写对照(等价的五字段写法):

简写等价于含义
@reboot(无等价字段)cron 守护进程每次启动时执行一次
@yearly / @annually0 0 1 1 *每年 1 月 1 日 0 点
@monthly0 0 1 * *每月 1 日 0 点
@weekly0 0 * * 0每周日 0 点
@daily / @midnight0 0 * * *每天 0 点
@hourly0 * * * *每小时整点

💡 要点:@reboot 的价值在于「开机后执行一次」的初始化任务,但它依赖 cron 守护进程被启动(开机不自启 cron 的机器上 @reboot 永远不会触发)。

3.6 落盘位置与权限:/var/spool/cron/crontabs/root

crontab 不是存在家目录,而是在专属 spool 目录。装一条任务后实测:

$ echo '*/1 * * * * date > /root/demo/crontab/ran.txt' | crontab -; echo rc=$?
rc=0

$ ls -la /var/spool/cron/crontabs/
total 12
drwx-wx--T 2 root crontab 4096 Oct 15 23:50 .
drwxr-xr-x 5 root root    4096 Oct 15 23:22 ..
-rw------- 1 root crontab  221 Oct 15 23:50 root

$ cat /var/spool/cron/crontabs/root
# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (- installed on Thu Oct 15 23:50:33 2026)
# (Cron version -- $Id: crontab.c,v 2.13 1994/01/17 03:20:37 vixie Exp $)
*/1 * * * * date > /root/demo/crontab/ran.txt

逐项解读:

  • 文件名 = 用户名:root 的任务表就是 /var/spool/cron/crontabs/root,tester 的就是同名文件;
  • 权限 600(-rw-------),属主 root:crontab:只有属主用户与 crontab 组能读,其他用户连文件名都看不全(目录本身是 drwx-wx--T,无读权限);
  • 头三行注释是 crontab 程序自动加的:明确警告不要直接编辑此文件——它由 crontab 命令生成,直接改会在下次安装时被覆盖,且格式写坏会导致整个任务表失效。

💡 要点:Red Hat/CentOS 系的 spool 路径是 /var/spool/cron/用户名(少一层 crontabs 目录),迁移脚本时注意路径差异。备份就是把这个目录下的文件拷走,或用 crontab -l > 备份文件。

3.7 -u:操作其他用户的 crontab(仅限 root)

-u 指定目标用户。root 给 tester 查询、安装:

$ crontab -u tester -l; echo rc=$?
no crontab for tester
rc=1

$ echo '30 3 * * * echo tester-job' | crontab -u tester -; echo rc=$?
rc=0

$ crontab -u tester -l
30 3 * * * echo tester-job

tester 自己查询自己的任务表(不带 -u)正常;普通用户试图用 -u 操作别人,直接被特权校验拦截:

$ su tester -c "crontab -l"; echo rc=$?
30 3 * * * echo tester-job
rc=0

$ su tester -c "crontab -u root -l"; echo rc=$?
must be privileged to use -u
rc=1

💡 要点:must be privileged to use -u 是权限边界报错——-u 只对 root(更准确地说是对能写 spool 的用户)开放。给业务账户部署定时任务的推荐路径:root 用 -u 账户名 安装,或让账户自己 crontab -e。

3.8 -r:删除 crontab

$ crontab -r; echo rc=$?
rc=0

$ crontab -l; echo rc=$?
no crontab for root
rc=1

💡 要点:-r 整表删除、无确认、不可恢复。cron 的 -r 有个历史陷阱:部分老版本在手抖时把 -r 敲成回车误触——所以下面的 -ri 才是运维推荐写法。删除后 spool 目录里对应文件一并消失(3.6 节的 ls 可复核)。

3.9 -ri:删除前的交互确认

-i 必须与 -r 连用,删除前询问。回答 y 才真的删:

$ echo '*/1 * * * * true' | crontab -

$ echo y | crontab -ri; echo rc=$?
crontab: really delete root's crontab? (y/n) rc=0

$ crontab -l; echo rc=$?
no crontab for root
rc=1

回答 n 则保留原表:

$ echo '*/1 * * * * true' | crontab -

$ echo n | crontab -ri; echo rc=$?
crontab: really delete root's crontab? (y/n) rc=0

$ crontab -l; echo rc=$?
*/1 * * * * true
rc=0

💡 要点:确认提示不带换行,回显里提示与后续输出粘在一行属正常现象;交互答案读自 stdin,因此自动化脚本里可以 echo y | crontab -ri,但更建议保留数据时用 4.2 节的备份流程而不是脚本里盲答 y。

3.10 非法字段:安装被拒且旧表不丢

时间字段越界时安装直接失败(实测分钟写成 61):

$ echo '61 * * * * true' | crontab -; echo rc=$?
"-":0: bad minute
errors in crontab file, can't install.
rc=1

$ crontab -l; echo rc=$?
no crontab for root
rc=1

💡 要点:crontab 安装时会做字段合法性校验(范围、字段数),报错定位精确到「文件名:行号: 字段名」("-":0 表示来自标准输入的第 0 行)。报错时旧任务表保持原样,不会被半成品污染——这比很多配置系统的行为安全。

3.11 执行实证:等 65 秒看 cron 真的跑起来

装上每分钟任务后,删掉产物、记录开始时间,等 65 秒再看结果(cron 按整分钟触发,65 秒窗口必然覆盖一次触发点):

$ rm -f /root/demo/crontab/ran.txt; date
Thu Oct 15 23:50:33 UTC 2026

(等待 65 秒)

$ date
Thu Oct 15 23:51:38 UTC 2026

$ cat /root/demo/crontab/ran.txt
Thu Oct 15 23:51:01 UTC 2026

$ ls -l /root/demo/crontab/
total 4
-rw-r--r-- 1 root root 29 Oct 15 23:51 ran.txt

$ grep CRON /var/log/syslog | tail -3
Oct 15 23:51:01 f1034b9326b2 CRON[21995]: (root) CMD (date > /root/demo/crontab/ran.txt)

三重证据链:产物 ran.txt 存在且内容是 23:51:01 的时间戳(秒位是 01——正好在整分钟触发点);文件时间戳 23:51;syslog 里 CRON 进程记录了 (root) CMD (date > ...) 的执行行。注意开始等的时候是 23:50:33,任务在下一个整分钟 23:51:01 触发——cron 的最小调度粒度是 1 分钟,且对齐整分钟边界。

💡 要点:这 65 秒的等待是验证定时任务「真的会跑」的黄金手段——crontab 语法正确不代表任务能执行(还要看 cron 守护进程、环境变量、路径权限)。排查「任务不执行」按本节三连反向走:service cron status 确认守护进程 → syslog 里找 CRON 执行行确认已触发 → 没有执行行就是时间字段写错,有执行行没产物就是命令本身的问题。

3.12 技术拓展:Linux 定时调度体系对比

「定时执行」在 Linux 上不止 cron 一套,主流机制横向对比——

机制调度模型最小粒度典型用途
cron(crontab)周期性时间表(5 字段)1 分钟常规周期任务(备份/巡检/报表)
anacron按「距上次执行的天数」补偿错过的任务1 天非全天开机的机器补跑日常任务
systemd timerunit 定时器(OnCalendar/OnUnitActiveSec)秒级现代 Ubuntu 的推荐方案,日志走 journal
at / batch一次性未来时间点1 分钟只跑一次的延时任务(见本专栏 at 篇)
sleep + 后台脚本进程内延时秒级临时脚本内的简单等待

💡 关键差异一句话:cron 管周期、at 管单次、systemd timer 是二者的现代替代。本文以 crontab 为主线(Ubuntu 22.04 默认安装、全发行版通用、语法五十年未变);cron 依赖机器持续在线,可能错过的补偿场景选 anacron,需要秒级精度或依赖编排时选 systemd timer。

四、实战示例

4.1 场景一:添加定时任务的标准闭环

「写入 → 回读确认 → 等待 → 验证执行 → 核对日志」五步闭环,每步都有回显才算部署完成:

$ echo '*/1 * * * * date > /root/demo/crontab/ran.txt' | crontab -; echo rc=$?
rc=0

$ crontab -l
*/1 * * * * date > /root/demo/crontab/ran.txt

$ rm -f /root/demo/crontab/ran.txt; date
Thu Oct 15 23:50:33 UTC 2026

(等待 65 秒)

$ cat /root/demo/crontab/ran.txt
Thu Oct 15 23:51:01 UTC 2026

验收标准:-l 能回读、等待一个调度周期后产物按预期生成(3.11 节的日志核对可作为第六步)。

4.2 场景二:修改任务表而不丢原有任务(备份 → 编辑 → 重装)

crontab 的安装是整表替换,所以改任务的正确姿势是「先导出、再编辑、后整体装回」:

$ echo '0 5 * * * echo nightly' | crontab -; echo rc=$?
rc=0

$ crontab -l
0 5 * * * echo nightly

$ crontab -l > /root/demo/crontab/backup.txt; cat /root/demo/crontab/backup.txt
0 5 * * * echo nightly

$ echo '30 6 * * * echo morning' >> /root/demo/crontab/backup.txt; cat /root/demo/crontab/backup.txt
0 5 * * * echo nightly
30 6 * * * echo morning

$ crontab /root/demo/crontab/backup.txt; echo rc=$?
rc=0

$ crontab -l
0 5 * * * echo nightly
30 6 * * * echo morning

环境变量行与注释行同样走这个流程原样保留,实测装入带 PATH= 行的表:

$ printf 'PATH=/usr/local/bin:/usr/bin:/bin\n*/1 * * * * true\n' | crontab -; echo rc=$?
rc=0

$ crontab -l
PATH=/usr/local/bin:/usr/bin:/bin
*/1 * * * * true

💡 说明:任务由 cron 执行时的 PATH 与登录 shell 不同(默认较精简),命令写绝对路径或在表头加 PATH= 行是最稳的两种做法。

4.3 场景三:给业务账户部署定时任务

root 通过 -u 替 tester 部署、验证、回收(完整生命周期):

$ crontab -u tester -l; echo rc=$?
no crontab for tester
rc=1

$ echo '30 3 * * * echo tester-job' | crontab -u tester -; echo rc=$?
rc=0

$ crontab -u tester -l
30 3 * * * echo tester-job

$ su tester -c "crontab -l"; echo rc=$?
30 3 * * * echo tester-job
rc=0

$ crontab -u tester -r; echo rc=$?
rc=0

💡 说明:任务里写的命令以 tester 身份执行(其家目录、权限都按 tester 算);回收用 crontab -u tester -r,别忘了这一步——残留任务会在账号删除后继续尝试执行(cron 对已删用户的行为取决于系统配置,清理干净最稳妥)。

4.4 场景四:任务不执行时的排查前置件

任务「装了不跑」时按顺序确认三件事。第一,cron 服务在跑:

$ service cron status; echo rc=$?
 * cron is running
rc=0

第二,系统有 syslog 落盘能力(最小化系统没有 rsyslog 时,cron 日志不会出现在 /var/log/syslog,先装并启动它——本环境实测:apt-get install -y rsyslog 后 init 脚本不存在,直接前台启动守护进程即可):

$ apt-get install -y -qq rsyslog
(安装过程略,成功后 rc=0)

$ service rsyslog start; echo rc=$?
rsyslog: unrecognized service
rc=1

$ rsyslogd
rsyslogd: imklog: cannot open kernel log (/proc/kmsg): Operation not permitted.
rsyslogd: activation of module imklog failed [v8.2112.0 try https://www.rsyslog.com/e/2145 ]

$ logger rsyslog-ready-test2; sleep 1; grep rsyslog-ready-test2 /var/log/syslog
Oct 15 23:50:01 f1034b9326b2 root: rsyslog-ready-test2

💡 说明:service rsyslog start 报 unrecognized service 是因为该环境没有 rsyslog 的 SysV 脚本,直接运行 rsyslogd 即可工作;imklog 告警只是读不了内核日志,不影响用户态日志收集。以 systemd 引导的标准 Ubuntu 服务器上用 systemctl status rsyslog 检查。

第三,日志里看 cron 是否记录了执行(执行行与 MTA 提示行):

$ grep CRON /var/log/syslog | tail -3
Oct 15 23:51:01 f1034b9326b2 CRON[21995]: (root) CMD (date > /root/demo/crontab/ran.txt)

判读方法:日志里有 CMD 行说明 cron 触发了,任务本身的问题去查命令;连 CMD 行都没有说明任务没被调度(时间字段写错、cron 服务没跑、任务表没装上);出现 (CRON) info (No MTA installed, discarding output) 说明命令有输出但系统没装邮件传输代理,输出被丢弃(安装 postfix 等可接收,或让命令自带重定向)。

五、注意事项与常见问题

Q1:裸敲 crontab 回车会有什么后果? 等于用 stdin 的内容整表替换当前任务表;stdin 为空/立即 EOF 时装成空表、rc=0 且无提示(3.1 节实测)。已部署的任务会瞬间清空且无确认。养成习惯:crontab 后面永远跟参数;批量变更走「导出 → 编辑 → 装回」(4.2 节)。

Q2:任务装上了却没执行,最常见的原因有哪些? 按命中率排序:cron 服务没运行(先 service cron status);时间字段写错(用 3.11 节的等待法验证);命令 PATH 不全(加 PATH= 行或绝对路径,4.2 节实测);命令里的 % 未转义(见 Q5);环境差异(cron 执行环境无终端、无登录 shell 的环境变量)。

Q3:cron 能每 30 秒跑一次吗? 不能。cron 的最小粒度是 1 分钟,且对齐整分钟边界(3.11 节实测产物时间戳秒位为 01)。需要秒级调度应换 systemd timer(OnCalendar 支持亚分钟)或常驻进程。变通写法(同一分钟内 sleep 30 再跑一次的第二条任务行)只是绕路,不改变调度粒度本质。

Q4:Ubuntu 上服务名叫 cron 还是 crond?文件放哪? Ubuntu/Debian 系是 cron(service cron status),Red Hat/CentOS 系才是 crond。用户任务表 Ubuntu 在 /var/spool/cron/crontabs/用户名,Red Hat 系在 /var/spool/cron/用户名。跨发行版迁移脚本时这两个拼写差异是高频翻车点。

Q5:命令里的 % 为什么导致任务行为异常? cron 把任务命令中第一个未转义的 % 之后的所有内容当作命令的标准输入(其中 % 按换行处理),而不是命令的一部分。实测任务 * * * * * echo 100% done > /root/demo/crontab/pct.txt:syslog 记录的执行命令被截断为 CMD (echo 100),重定向根本没生效,文件从未生成,输出因无 MTA 被丢弃——

$ crontab -l
* * * * * echo 100% done > /root/demo/crontab/pct.txt

$ grep CRON /var/log/syslog | grep "echo 100"
Oct 15 23:55:01 f1034b9326b2 CRON[22062]: (root) CMD (echo 100)
Oct 15 23:55:01 f1034b9326b2 CRON[22060]: (CRON) info (No MTA installed, discarding output)

$ ls -l /root/demo/crontab/
total 8
-rw-r--r-- 1 root root 47 Oct 15 23:54 backup.txt
-rw-r--r-- 1 root root 29 Oct 15 23:51 ran.txt

需要字面 % 时写成 \%(或在脚本内处理),涉及日期格式化(如 date +\%F)时尤其注意。

Q6:crontab 与系统级 /etc/crontab、/etc/cron.d/ 什么关系? crontab -l 管的是「用户级」任务表(spool 目录);/etc/crontab 与 /etc/cron.d/* 是「系统级」任务表,格式多一列用户名(*/10 * * * * root command 形式),由管理员直接编辑文件,不走 crontab 命令。本环境日志里出现的 CMD (command -v debian-sa1 ...) 就是 sysstat 包放在系统级任务表里的任务。批量部署随软件包分发的任务用 /etc/cron.d/,用户自助任务用 crontab。

Q7:-e 编辑器打不开/不想进编辑器怎么办? -e 依赖环境变量 EDITOR/VISUAL 指向的交互编辑器。非交互场景(脚本、批量)用本文主线流程:crontab -l > 备份 → 任意方式改文件 → crontab 文件 装回(4.2 节实测),行为与 -e 等价且可控。

六、参考链接