Linux小课堂: 定时与延时执行机制之date、at、sleep 与 crontab 的深度解析

系统时间管理:date 命令的精确控制

在 Linux 系统中,时间是任务调度的核心要素。掌握系统时间的查看与修改,是实现定时和延时执行的前提

date 命令不仅是查看当前时间的工具,更是格式化输出和修改系统时间的核心命令。其功能远超简单的"显示时间",具备高度可定制性

1 ) 查看当前系统时间

使用 date 命令可输出当前系统的完整时间信息:

bash 复制代码
$ 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)

示例:

bash 复制代码
输出当前时分秒
$ date "+%H:%M:%S"
19:22:53
 
输出人性化格式
$ date "+%H时%M分%S秒"
19时22分53秒
 
输出年份
$ date "+%Y"
2019

注意:只有紧跟 % 的字符才会被解析为时间字段,其余文本原样输出。

可通过查阅手册获取完整格式列表:

bash 复制代码
man date

3 ) 修改系统时间(需 root 权限)
date 不仅用于读取时间,还可修改系统时间。命令语法为:

bash 复制代码
sudo date MMDDhhmm[[YY]YY]

其中参数含义如下:

  • MM:月份
  • DD:日期
  • hh:小时
  • mm:分钟
  • YY:可选年份

示例:

bash 复制代码
将时间设为 2019 年 10 月 12 日 14:30
$ sudo date 10121430

执行后系统时间将变更,但若启用了网络时间同步(NTP),系统将在一段时间后自动校正回真实时间。

该命令遵循格式:MMDDhhmm[[YY]YY](月日时分)。若未指定年份,则保留当前年;秒数默认为零

修改后可通过再次运行 date 验证:

bash 复制代码
date  # 显示:Sat Oct 12 14:30:06 CST 2019

4 ) 启用自动时间同步

尽管可手动修改时间,但现代 Linux 系统通常启用自动时间同步服务(NTP)。

确保系统设置中开启自动时区与时间同步功能(通常位于 Settings → Date & Time → Automatic Timezone

一旦联网,系统会定期从 NTP 服务器获取准确时间,保障时间一致性

bash 复制代码
检查是否开启自动时区同步
timedatectl status 
 
启用自动时间同步
sudo timedatectl set-ntp true

Automatic Timezone 开启时,系统会周期性连接全球时间服务器进行校正

这意味着即使手动修改时间,联网后仍会被重置回正确值

一次性延时执行:at 命令的灵活应用

当需要在某个特定时间点仅执行一次任务时,应使用 at 命令

1 )安装 at 服务(如未预装)

bash 复制代码
CentOS/RHEL 系列 (yum/dnf)
yum install at -y
 
Ubuntu/Debian 系列 
apt-get install at -y
 
启动并设置开机自启
sudo systemctl enable atd
sudo systemctl start atd

2 ) 指定绝对时间执行

语法结构为:

bash 复制代码
at [时间] [日期可选]

进入交互模式后输入要执行的命令,最后按 Ctrl+D 提交

示例:

bash 复制代码
$ at 22:10 tomorrow
at> cp ~/fire.txt ~/fire_copy.txt
at> <Ctrl+d>

输出:

log 复制代码
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 )使用相对时间延迟执行

bash 复制代码
$ at now + 10 minutes
at> echo "Backup completed" >> /var/log/backup.log
at> <Ctrl+d>

支持的关键字包括:

  • minutes
  • hours
  • days
  • weeks
  • months
  • years

例如:

bash 复制代码
at now + 7 weeks     # 七周后执行 
at now + 1 month     # 一个月后执行

表示七周后的同一时间执行

4 )查看与删除待执行任务

  • 列出所有待处理任务:

    bash 复制代码
    $ atq
    1   Mon Sep  2 22:10:00 2019 a oskar 
    2   Mon Sep  2 19:52:00 2019 a oskar
  • 删除指定任务:

    bash 复制代码
    atrm 1    # 删除 job ID 为 1 的任务
    atrm 2

多次调用 atq 可验证任务是否已被清除

验证是否清空:

bash 复制代码
atq       # 应无输出

进程间暂停控制:sleep 命令实现时间间隔

sleep 命令允许在多个命令之间插入暂停,常用于脚本中的延时逻辑

1 ) 基本语法

bash 复制代码
sleep [数值][单位]

2 )基本用法

bash 复制代码
$ touch file.txt; sleep 10; rm file.txt

上述命令序列含义为:

  1. 创建文件 file.txt
  2. 暂停 10 秒
  3. 删除该文件

默认单位为秒

3 )支持多种时间单位

可通过后缀指定时间单位:

  • s:秒(默认)
  • m:分钟
  • h:小时
  • d:天

扩展示例:

bash 复制代码
touch ~/temp.txt; sleep 15m; rm ~/temp.txt    # 15分钟后删除
sleep 2h; echo "Two hours passed"            # 两小时后输出

重要提示:sleep 是阻塞式命令,期间 shell 不会执行后续指令,直到计时结束。

多命令连接控制符:;&&|| 的语义差异

在单行中组合多个命令时,连接符的选择直接影响执行流程。

连接符 含义 是否受前命令影响
; 顺序执行 否,无论成败均继续
&& 逻辑与(成功才继续) 是,前命令成功才执行后续
` `

实际应用场景对比:

bash 复制代码
# 无论 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

在命令链中引入逻辑判断,可提升脚本健壮性和效率

最佳实践建议:在自动化脚本中优先使用 &&|| 提高健壮性

综合应用

bash 复制代码
command1 && command2 || command3

等价于:尝试执行 command1,成功则运行 command2,否则运行 command3

周期性定时任务:crontab 的强大调度能力

对于重复性自动化任务,Linux 提供了强大的 crontab 工具

它基于配置文件定义任务执行计划,并由后台守护进程 cron 调度执行

1 ) crontab 架构说明

  • crontab:用户级命令,用于编辑、查看、删除定时任务
  • cron 守护进程:后台服务,负责按计划触发任务执行

每个用户拥有独立的 crontab 配置文件,存储于 /var/spool/cron/<username>

2 ) 安装与启动 cron 服务

bash 复制代码
# CentOS/RHEL 
yum install cronie -y
systemctl enable crond
systemctl start crond
# 或
yum install crontabs -y
systemctl enable crond
systemctl start crond

Ubuntu/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

bash 复制代码
echo 'export EDITOR=nano' >> ~/.bashrc
source ~/.bashrc

此配置使 crontab -e 自动调用 nano 编辑器

4 ) crontab 配置语法结构

每条任务格式为五行时间字段加一条命令:

ss 复制代码
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

每条规则由六部分构成,格式如下:

tree 复制代码
- * * * * 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 示例

bash 复制代码
# 每天 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),防止环境变量缺失导致命令找不到

再举一些经典应用场景示例

bash 复制代码
# 每小时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

推荐最佳实践

bash 复制代码
# 使用绝对路径调用脚本和命令
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 删除所有定时任务(不可逆,请慎用)

示例流程:

bash 复制代码
$ 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 接口示例。

项目初始化

bash 复制代码
npm i -g @nestjs/cli
nest new cron-manager
cd cron-manager
npm install child_process util

Cron Service 实现(精准操作底层)

ts 复制代码
// 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

ts 复制代码
// 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 注册

ts 复制代码
// 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 或具备权限)

bash 复制代码
启动 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 化任务管理系统。以下是一个完整的代码示例,模拟注册定时任务并与系统集成。

项目结构:

tree 复制代码
/src
  /cron
    cron.service.ts
    cron.controller.ts
  app.module.ts

cron.service.ts

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

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

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 {}

启动服务并测试:

bash 复制代码
安装依赖 
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 模块实现应用内定时任务。

安装依赖

bash 复制代码
npm install @nestjs/schedule 
npm install -D @types/cron

启用 ScheduleModule

typescript 复制代码
// 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 {}

定义定时任务

typescript 复制代码
// 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('清理旧日志...');
  }
}

动态任务管理(高级)

typescript 复制代码
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:10at now + 10 minatqatrm 单次 未来某刻执行一次任务
sleep 命令间暂停 sleep 10sleep 5m 内嵌于命令流 脚本内部延时控制
连接符 控制执行逻辑 ;(顺序)、&&(成功才执行)、` `(失败才执行)
crontab 周期性定时任务 crontab -ecrontab -lcrontab -r 多次 日常维护、定期备份、健康检查

核心原则:

  • 若只需一次延迟执行 → 使用 at
  • 若需周期性重复 → 使用 crontab
  • 若在脚本中控制节奏 → 使用 sleep
  • 若需获取或设置时间 → 使用 date

最终结论

Linux 下的时间控制体系完备而精密。

  • 使用 date 掌控系统时间基准;
  • 利用 at 实现单次未来执行;
  • 借助 sleep 在脚本中嵌入等待逻辑;
  • 通过 ;&&\|\| 精细控制命令链;
  • 最终依靠 crontab 构建长期稳定的自动化运维机制。

重点强调:所有涉及时间调度的操作都应优先使用绝对路径调用命令,并在测试阶段充分验证语法正确性,避免因环境差异造成任务失效。

Linux 下的定时与延时执行机制构成了自动化运维的基础。从精确到秒的 sleep 控制,到灵活的时间表达式 at,再到强大稳定的 crontab 周期调度,配合 date 对时间本身的掌控,构成了完整的任务调度生态。

掌握这些命令,不仅能够提升日常操作效率,更为构建自动化脚本、监控系统、CI/CD 流程提供了坚实基础。结合现代开发框架如 NestJS,更能实现可视化的任务管理平台,推动 DevOps 实践落地。

相关推荐
A小辣椒2 小时前
TShark:Wireshark CLI 功能
linux
A小辣椒6 小时前
TShark:基础知识
linux
AlfredZhao8 小时前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao1 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户9718356334661 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪1 天前
linux 拷贝文件或目录到指定的位置
linux
大树882 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠2 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质2 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
bush42 天前
嵌入式linux学习记录十四、术语
linux·嵌入式