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 实践落地。

相关推荐
weixin_4624462316 小时前
ubuntu/kali安装k8s
linux·ubuntu·kubernetes
lys_82817 小时前
【linux】解决NAT模型下使用Xshell连接虚拟机显示22端口connection failed问题
linux·运维·服务器
Mxsoft61917 小时前
电力系统智能运维网络安全威胁检测与防御策略
运维·安全·web安全
序属秋秋秋18 小时前
《Linux系统编程之系统导论》【冯诺依曼体系结构 + 操作系统基本概述】
linux·运维·服务器·c语言·ubuntu·操作系统·冯诺依曼体系结构
她说彩礼65万19 小时前
C# 特性详解
linux·服务器·c#
LSL666_21 小时前
5 Repository 层接口
android·运维·elasticsearch·jenkins·repository
Hi202402171 天前
消除FFmpeg库的SONAME依赖
linux·ffmpeg
电棍2331 天前
在docker a100云服务器运行vulkan->sapien->robotwin的经验(报错segmentation fault)
运维·docker·容器
gfanbei1 天前
ARM V8 Cortex R52 上电运行在什么状态?— Deepseek 解答
linux·arm开发·嵌入式硬件
liu****1 天前
14.日志封装和线程池封装
linux·开发语言·c++