Linux小课堂: 定时与延时执行机制之date、at、sleep 与 crontab 的深度解析
系统时间管理:date
命令的精确控制
在 Linux 系统中,时间是任务调度的核心要素。掌握系统时间的查看与修改,是实现定时和延时执行的前提
date
命令不仅是查看当前时间的工具,更是格式化输出和修改系统时间的核心命令。其功能远超简单的“显示时间”,具备高度可定制性
1 ) 查看当前系统时间
使用 date
命令可输出当前系统的完整时间信息:
$ date
Mon Sep 2 19:18:45 CST 2019
该输出包含星期、月日、时间及所在时区(CST 表示中国标准时间)。
2 )自定义时间格式输出
通过 +
符号后接格式化占位符,可自定义输出内容。常见格式标识如下:
%H
:小时(00–23)%M
:分钟(00–59)%S
:秒(00–59)%Y
:四位年份(如 2019)%m
:月份(01–12)%d
:日期(01–31)
示例:
输出当前时分秒
$ date "+%H:%M:%S"
19:22:53输出人性化格式
$ date "+%H时%M分%S秒"
19时22分53秒输出年份
$ date "+%Y"
2019
注意:只有紧跟 %
的字符才会被解析为时间字段,其余文本原样输出。
可通过查阅手册获取完整格式列表:
man date
3 ) 修改系统时间(需 root 权限)
date
不仅用于读取时间,还可修改系统时间。命令语法为:
sudo date MMDDhhmm[[YY]YY]
其中参数含义如下:
MM
:月份DD
:日期hh
:小时mm
:分钟YY
:可选年份
示例:
将时间设为 2019 年 10 月 12 日 14:30
$ sudo date 10121430
执行后系统时间将变更,但若启用了网络时间同步(NTP),系统将在一段时间后自动校正回真实时间。
该命令遵循格式:MMDDhhmm[[YY]YY]
(月日时分[年])。若未指定年份,则保留当前年;秒数默认为零
修改后可通过再次运行 date
验证:
date # 显示:Sat Oct 12 14:30:06 CST 2019
4 ) 启用自动时间同步
尽管可手动修改时间,但现代 Linux 系统通常启用自动时间同步服务(NTP)。
确保系统设置中开启自动时区与时间同步功能(通常位于 Settings → Date & Time → Automatic Timezone
)
一旦联网,系统会定期从 NTP 服务器获取准确时间,保障时间一致性
检查是否开启自动时区同步
timedatectl status 启用自动时间同步
sudo timedatectl set-ntp true
当 Automatic Timezone
开启时,系统会周期性连接全球时间服务器进行校正
这意味着即使手动修改时间,联网后仍会被重置回正确值
一次性延时执行:at
命令的灵活应用
当需要在某个特定时间点仅执行一次任务时,应使用 at
命令
1 )安装 at 服务(如未预装)
CentOS/RHEL 系列 (yum/dnf)
yum install at -yUbuntu/Debian 系列
apt-get install at -y启动并设置开机自启
sudo systemctl enable atd
sudo systemctl start atd
2 ) 指定绝对时间执行
语法结构为:
at [时间] [日期可选]
进入交互模式后输入要执行的命令,最后按 Ctrl+D
提交
示例:
$ at 22:10 tomorrow
at> cp ~/fire.txt ~/fire_copy.txt
at> <Ctrl+d>
输出:
job 1 at Sun Sep 1 22:10:00 2019
终端提示 job 1 at ...
,表示已创建编号为 1 的任务,在当日 22:10 执行创建文件操作。
支持的时间表达方式包括:
tomorrow
:明天同一时间12/10/19
:美国格式日期(月/日/年)now + 10 minutes
:10 分钟后
3 )使用相对时间延迟执行
$ at now + 10 minutes
at> echo "Backup completed" >> /var/log/backup.log
at> <Ctrl+d>
支持的关键字包括:
minutes
hours
days
weeks
months
years
例如:
at now + 7 weeks # 七周后执行
at now + 1 month # 一个月后执行
表示七周后的同一时间执行
4 )查看与删除待执行任务
-
列出所有待处理任务:
$ atq 1 Mon Sep 2 22:10:00 2019 a oskar 2 Mon Sep 2 19:52:00 2019 a oskar
-
删除指定任务:
atrm 1 # 删除 job ID 为 1 的任务 atrm 2
多次调用 atq
可验证任务是否已被清除
验证是否清空:
atq # 应无输出
进程间暂停控制:sleep
命令实现时间间隔
sleep
命令允许在多个命令之间插入暂停,常用于脚本中的延时逻辑
1 ) 基本语法
sleep [数值][单位]
2 )基本用法
$ touch file.txt; sleep 10; rm file.txt
上述命令序列含义为:
- 创建文件
file.txt
- 暂停 10 秒
- 删除该文件
默认单位为秒
3 )支持多种时间单位
可通过后缀指定时间单位:
s
:秒(默认)m
:分钟h
:小时d
:天
扩展示例:
touch ~/temp.txt; sleep 15m; rm ~/temp.txt # 15分钟后删除
sleep 2h; echo "Two hours passed" # 两小时后输出
重要提示:sleep
是阻塞式命令,期间 shell 不会执行后续指令,直到计时结束。
多命令连接控制符:;
、&&
与 ||
的语义差异
在单行中组合多个命令时,连接符的选择直接影响执行流程。
连接符 | 含义 | 是否受前命令影响 |
---|---|---|
; | 顺序执行 | 否,无论成败均继续 |
&& | 逻辑与(成功才继续) | 是,前命令成功才执行后续 |
|| | 逻辑或(失败才继续) | 是,前命令失败才执行后续 |
实际应用场景对比:
# 无论 touch 是否成功,都会尝试删除(不推荐)
# 这与管道 `|` 不同,后者传递数据流,而分号仅控制执行顺序。
touch bad_path/file.txt; rm file.txt# `&&`:逻辑与(仅当前命令成功才执行后续)
# 只有创建成功,才进行删除(安全做法)
touch ~/safe.txt && rm ~/safe.txt# `||`:逻辑或(仅当前命令失败才执行后续)
# 若备份失败,则发送警报邮件
rsync -av /data/ backup/ || echo "Backup failed!" | mail -s "Alert" admin@local
在命令链中引入逻辑判断,可提升脚本健壮性和效率
最佳实践建议:在自动化脚本中优先使用 &&
和 ||
提高健壮性
综合应用
command1 && command2 || command3
等价于:尝试执行 command1
,成功则运行 command2
,否则运行 command3
周期性定时任务:crontab
的强大调度能力
对于重复性自动化任务,Linux 提供了强大的 crontab
工具
它基于配置文件定义任务执行计划,并由后台守护进程 cron
调度执行
1 ) crontab 架构说明
crontab
:用户级命令,用于编辑、查看、删除定时任务cron
守护进程:后台服务,负责按计划触发任务执行
每个用户拥有独立的 crontab
配置文件,存储于 /var/spool/cron/<username>
2 ) 安装与启动 cron 服务
# CentOS/RHEL
yum install cronie -y
systemctl enable crond
systemctl start crond
# 或
yum install crontabs -y
systemctl enable crond
systemctl start crondUbuntu/Debian
apt-get install cron -y
systemctl enable cron
systemctl start cron
cronie 是CentOS中提供定时任务(crontab)功能的核心软件包,包含crontab命令工具和crond服务(定时任务守护进程)
crontabs 并非独立安装包,而是cronie包的一部分(或部分发行版中可能作为依赖存在),直接使用yum install crontabs可能无法正确安装完整功能
3 ) 设置默认编辑器为 nano
避免因 vi
编辑器难以上手导致配置错误,建议设置默认编辑器为 nano
:
echo 'export EDITOR=nano' >> ~/.bashrc
source ~/.bashrc
此配置使 crontab -e
自动调用 nano
编辑器
4 ) crontab 配置语法结构
每条任务格式为五行时间字段加一条命令:
min hour dom mon dow command
各字段含义如下:
字段 | 含义 | 取值范围 |
---|---|---|
min | 分钟 | 0–59 |
hour | 小时 | 0–23 |
dom | 一个月中的哪一天 | 1–31 |
mon | 月份 | 1–12 或 jan-dec |
dow | 星期几 | 0–7(0 和 7 都表示周日) |
command | 要执行的命令(推荐使用绝对路径) |
注意:五个时间字段之间必须用空格分隔,不能用 Tab
每条规则由六部分构成,格式如下:
- * * * * command-to-be-executed
│ │ │ │ │
│ │ │ │ └── Day of Week (0–7, 0 or 7 = Sunday)
│ │ │ └──── Month (1–12)
│ │ └────── Day of Month (1–31)
│ └──────── Hour (0–23)
└────────── Minute (0–59)
特殊符号说明:
*
:任意值,
:列举多个值(如1,3,5
)-
:范围(如1-15
)/
:步长(如*/2
表示每隔两个单位)
5 ) 实用 crontab 示例
# 每天 22:10 创建 fire.txt 文件(使用绝对路径更安全)
10 22 * * * /usr/bin/touch /home/oskar/fire.txt# 每小时第 47 分钟执行一次 sync 操作
47 * * * * /usr/bin/sync# 每周一凌晨 00:00 清理临时目录
0 0 * * 1 /usr/bin/rm -rf /tmp/*# 每周一凌晨执行备份 `dow=1` 表示星期一
0 0 * * 1 /backup/script.sh# 月初至月中(1–15日)每天 5:30 执行数据库备份
30 5 1-15 * * /backup/db_backup.sh# 每周一、三、五凌晨运行日志归档
0 0 * * 1,3,5 /scripts/archive_logs.sh# 每两小时整点执行健康检查 `*/2` 在 hour 字段表示每两小时
0 */2 * * * /monitor/check_system.sh# 工作日(周一至周五)每十分钟执行一次数据同步
-/10 * * * 1-5 /sync/data_sync.sh
强烈建议:使用全路径调用命令(如 /usr/bin/touch
而非 touch
),防止环境变量缺失导致命令找不到
再举一些经典应用场景示例
# 每小时47分执行备份
47 * * * * /usr/local/bin/backup.sh# 每周一凌晨0点清理日志
0 0 * * 1 find /var/log -name "*.log" -mtime +7 -delete# 每月1–15日 5:30 执行数据同步
30 5 1-15 * * /opt/scripts/sync_data.sh# 周一至周五每10分钟检测服务状态
-/10 * * * 1-5 /usr/bin/curl -f http://localhost:8080/health || systemctl restart myapp# 每两小时整点发送心跳通知
0 */2 * * * echo "Heartbeat: $(date)" | mail admin@company.com
推荐最佳实践
# 使用绝对路径调用脚本和命令
0 3 * * * /home/user/scripts/cleanup.sh# 重定向输出以防邮件风暴
0 2 * * * /backup/script.sh > /dev/null 2>&1# 记录执行日志便于排查
0 1 * * * /check/diskspace.sh >> /var/log/disk_check.log 2>&1# 避免并发冲突(使用锁机制)
* * * * * flock -n /tmp/lockfile.pid /path/to/script.sh
6 ) crontab 常用操作命令
命令 | 功能 |
---|---|
crontab -l | 列出当前用户的定时任务 |
crontab -e | 编辑定时任务(自动加载 EDITOR) |
crontab -r | 删除所有定时任务(不可逆,请慎用) |
示例流程:
$ crontab -l
no crontab for oskar$ crontab -e
添加以下内容并保存
10 22 * * * /usr/bin/touch ~/fire.txt$ crontab -l
10 22 * * * /usr/bin/touch ~/fire.txt$ crontab -r
$ crontab -l
no crontab for oskar
NestJS + TypeScript 实现 Linux 定时任务管理系统(扩展代码)
1 ) 方案1
为体现现代开发与系统运维结合的能力,以下提供一个基于 NestJS 的简易 crontab
管理 API 接口示例。
项目初始化
npm i -g @nestjs/cli
nest new cron-manager
cd cron-manager
npm install child_process util
Cron Service 实现(精准操作底层)
// src/cron/cron.service.ts
import { Injectable } from '@nestjs/common';
import { exec, execSync } from 'child_process';@Injectable()
export class CronService {private readonly CRON_EDITOR = process.env.EDITOR || 'nano';/* 获取当前用户的 crontab 内容*/getCrontab(): string {try {return execSync('crontab -l').toString().trim();} catch (err) {return ''; // 无任务时返回空}}/* 写入新的 crontab 内容(覆盖式)* @param content 多行字符串,每行为一条 cron 表达式*/setCrontab(content: string): void {const input = content.trim() ? content : '# Empty crontab\n';execSync(`echo '${input.replace(/'/g, `'\\''`)}' | crontab`);}/* 添加一条新任务(追加模式)*/addCrontabEntry(entry: string): void {let current = this.getCrontab();current += '\n' + entry.trim();this.setCrontab(current);}/* 删除所有定时任务*/clearCrontab(): void {execSync('crontab -r');}/* 检查 cron 服务状态*/isCronActive(): boolean {try {const output = execSync('systemctl is-active crond', { timeout: 5000 }).toString().trim();return output === 'active';} catch {try {const output = execSync('systemctl is-active cron', { timeout: 5000 }).toString().trim();return output === 'active';} catch {return false;}}}/* 异步执行任意命令(用于调试)*/async runCommand(cmd: string): Promise<string> {return new Promise((resolve, reject) => {exec(cmd, { timeout: 30000 }, (err, stdout, stderr) => {if (err) return reject(err);resolve(stdout);});});}
}
Controller 层暴露 REST API
// src/cron/cron.controller.ts
import { Controller, Get, Post, Delete, Body } from '@nestjs/common';
import { CronService } from './cron.service';@Controller('cron')
export class CronController {constructor(private readonly cronService: CronService) {}@Get()getStatus() {return {active: this.cronService.isCronActive(),tasks: this.cronService.getCrontab().split('\n').filter(Boolean),};}@Post('entry')addEntry(@Body('command') command: string) {const entry = `*/5 * * * * ${command}`; // 默认每 5 分钟执行this.cronService.addCrontabEntry(entry);return { success: true, entry };}@Post('raw')setRaw(@Body('content') content: string) {this.cronService.setCrontab(content);return { success: true };}@Delete('clear')clearAll() {this.cronService.clearCrontab();return { success: true, message: 'All cron jobs removed.' };}
}
Module 注册
// src/cron/cron.module.ts
import { Module } from '@nestjs/common';
import { CronController } from './cron.controller';
import { CronService } from './cron.service';@Module({controllers: [CronController],providers: [CronService],
})
export class CronModule {}
启动应用(需 root 或具备权限)
启动 NestJS 应用(监听 3000 端口)
npm run start 测试接口
curl http://localhost:3000/cron添加任务
curl -X POST http://localhost:3000/cron/entry \-H "Content-Type: application/json" \-d '{"command": "/usr/bin/touch /tmp/test.txt"}'
注意:生产环境中应加入身份认证、输入校验、日志审计等功能,并限制权限访问
2 ) 方案2
虽然 crontab
是底层调度器,但在实际开发中,我们常结合 Node.js/NestJS 构建 Web 化任务管理系统。以下是一个完整的代码示例,模拟注册定时任务并与系统集成。
项目结构:
/src/croncron.service.tscron.controller.tsapp.module.ts
cron.service.ts
import { Injectable } from '@nestjs/common';
import { exec } from 'child_process';
import { promisify } from 'util';const execAsync = promisify(exec);@Injectable()
export class CronService {async listJobs(): Promise<string> {try {const { stdout } = await execAsync('crontab -l');return stdout.trim() || '(no scheduled jobs)';} catch (error) {return '(no crontab set)';}}async addJob(minutes: number, hours: number, command: string): Promise<void> {const current = await this.listJobs();const newEntry = `${minutes} ${hours} * * * ${command}`;const combined = current.includes('(no') ? newEntry : `${current}\n${newEntry}`;// 写入临时文件并通过 crontab 导入await execAsync(`echo "${combined}" | crontab -`);}async clearAll(): Promise<void> {await execAsync('crontab -r');}
}
cron.controller.ts
import { Controller, Get, Post, Delete, Query } from '@nestjs/common';
import { CronService } from './cron.service';@Controller('cron')
export class CronController {constructor(private readonly cronService: CronService) {}@Get()async getJobs() {return { jobs: await this.cronService.listJobs() };}@Post()async scheduleJob(@Query('min') min: string,@Query('hour') hour: string,@Query('cmd') cmd: string,) {await this.cronService.addJob(+min, +hour, cmd);return { status: 'scheduled', min, hour, cmd };}@Delete('all')async removeAll() {await this.cronService.clearAll();return { status: 'all jobs removed' };}
}
app.module.ts
import { Module } from '@nestjs/common';
import { CronService } from './cron/cron.service';
import { CronController } from './cron/cron.controller';@Module({controllers: [CronController],providers: [CronService],
})
export class AppModule {}
启动服务并测试:
安装依赖
npm install @nestjs/core @nestjs/common rxjs启动应用(假设使用 nest-cli)
nest start测试 API
curl "http://localhost:3000/cron?min=10&hour=22&cmd=touch%20~/test.txt"
此系统实现了对 crontab
的安全封装,防止直接暴露高危命令,适合企业级运维平台集成
3 )方案3
虽然 crontab
是系统级方案,但在微服务架构中,也可使用 NestJS 的 @nestjs/schedule
模块实现应用内定时任务。
安装依赖
npm install @nestjs/schedule
npm install -D @types/cron
启用 ScheduleModule
// app.module.ts
import { Module } from '@nestjs/common';
import { ScheduleModule } from '@nestjs/schedule';
import { TaskService } from './task.service';@Module({imports: [ScheduleModule.forRoot()],providers: [TaskService],
})
export class AppModule {}
定义定时任务
// task.service.ts
import { Injectable } from '@nestjs/common';
import { Cron, Interval, Timeout } from '@nestjs/schedule';@Injectable()
export class TaskService {// 每天 22:10 执行@Cron('10 22 * * *')handleDailyFileCreation() {console.log(`创建文件 at ${new Date().toISOString()}`);// 调用文件系统模块创建文件}// 每小时47分执行@Cron('47 * * * *')handleHourlyBackup() {console.log('执行备份任务');}// 每周一凌晨0点@Cron('0 0 * * 1')handleWeeklyCleanup() {console.log('清理旧日志...');}
}
动态任务管理(高级)
import { CronJob } from 'cron';@OnApplicationBootstrap
async onApplicationBootstrap() {const job = new CronJob('10 22 * * *', () => {this.logger.log('动态任务触发');});job.start();
}
适用场景:配置热更新、多租户任务隔离、Web 控制台动态增删任务等
总结关键知识点凝练
技术点 | 核心作用 | 关键命令 | 执行次数 | 适用场景 |
---|---|---|---|---|
date | 时间读取与修改 | date "+%H:%M" 、sudo date MMDDhhmm | — | 获取/修改系统时间、格式化输出 |
at | 单次延时执行 | at 22:10 、at now + 10 min 、atq 、atrm | 单次 | 未来某刻执行一次任务 |
sleep | 命令间暂停 | sleep 10 、sleep 5m | 内嵌于命令流 | 脚本内部延时控制 |
连接符 | 控制执行逻辑 | ; (顺序)、&& (成功才执行)、|| (失败才执行) | — | 综合运用 |
crontab | 周期性定时任务 | crontab -e 、crontab -l 、crontab -r | 多次 | 日常维护、定期备份、健康检查 |
核心原则:
- 若只需一次延迟执行 → 使用
at
- 若需周期性重复 → 使用
crontab
- 若在脚本中控制节奏 → 使用
sleep
- 若需获取或设置时间 → 使用
date
最终结论
Linux 下的时间控制体系完备而精密。
- 使用
date
掌控系统时间基准; - 利用
at
实现单次未来执行; - 借助
sleep
在脚本中嵌入等待逻辑; - 通过
;
、&&
、\|\|
精细控制命令链; - 最终依靠
crontab
构建长期稳定的自动化运维机制。
重点强调:所有涉及时间调度的操作都应优先使用绝对路径调用命令,并在测试阶段充分验证语法正确性,避免因环境差异造成任务失效。
Linux 下的定时与延时执行机制构成了自动化运维的基础。从精确到秒的 sleep
控制,到灵活的时间表达式 at
,再到强大稳定的 crontab
周期调度,配合 date
对时间本身的掌控,构成了完整的任务调度生态。
掌握这些命令,不仅能够提升日常操作效率,更为构建自动化脚本、监控系统、CI/CD 流程提供了坚实基础。结合现代开发框架如 NestJS,更能实现可视化的任务管理平台,推动 DevOps 实践落地。