Linux at命令详解

at 命令用于在指定时间执行一次性任务,它允许用户安排一个或多个命令在特定时间运行一次,支持多种时间格式和灵活的调度语法。

一、命令简介

at 命令是一个用于安排一次性任务的命令行工具。与 cron 不同,cron 用于周期性的重复任务,而 at 用于只在特定时间运行一次的任务。at 命令非常灵活,支持多种时间格式和相对时间表示。

特点: 一次性任务调度、灵活的时间格式、支持标准输入、邮件通知、队列管理。

二、安装at命令

在大多数 Linux 发行版中,at 命令需要单独安装:

Ubuntu/Debian

sudo apt-get install at

CentOS/RHEL

sudo yum install at

# CentOS 8+使用dnf
sudo dnf install at

Fedora

sudo dnf install at

Arch Linux

sudo pacman -S at

启动at守护进程

# 启动atd服务
sudo systemctl start atd

# 设置开机自启
sudo systemctl enable atd

# 检查服务状态
sudo systemctl status atd

验证安装

at -V 2>/dev/null || at --version 2>/dev/null || echo "at命令已安装"

三、基本语法

at [选项] 时间
at -c 任务号
at -l [队列]
at -d 任务号
atq [队列]
atrm 任务号

四、常用选项

选项 说明
-f 文件--file=文件 从指定文件读取命令(而不是从标准输入)
-m--mail 任务完成后发送邮件给用户(即使没有输出)
-M--send-mail 任务完成后发送邮件给用户(仅当有输出时)
-l--list 列出所有待执行的任务(同atq)
-d 任务号--delete=任务号 删除指定的任务(同atrm)
-c 任务号--cat=任务号 显示指定任务的详细内容
-q 队列--queue=队列 指定队列(a-z,A-Z,默认队列是a)
-t 时间--time=时间 使用绝对时间格式[[CC]YY]MMDDhhmm[.ss]
-v--version 显示版本信息
-h--help 显示帮助信息
-V 显示版本信息
-b--batch 在系统负载较低时运行任务(已废弃)

五、时间格式详解

at 命令支持非常灵活的时间格式,包括绝对时间和相对时间:

1. 绝对时间格式

格式 示例 说明
HH:MM 14:30 今天的指定时间(24小时制)
HH:MM YYYY-MM-DD 14:30 2024-12-25 指定日期和时间的绝对时间
HH:MM MM/DD/YY 14:30 12/25/24 美国日期格式
HH:MM DD.MM.YY 14:30 25.12.24 欧洲日期格式
midnight midnight 午夜(00:00)
noon noon 中午(12:00)
teatime teatime 下午4点(16:00)

2. 相对时间格式

格式 示例 说明
now + 时间单位 now + 5 minutes 5分钟后
明天 + 时间 tomorrow 14:30 明天14:30
下周 + 时间 next week 下周的同一时间
下月 + 时间 next month 下月的同一时间
明年 + 时间 next year 明年的同一时间

3. 时间单位

支持的时间单位:minutes(分钟)、hours(小时)、days(天)、weeks(周)、months(月)、years(年)。

六、使用示例

示例1:基本使用(交互模式)

# 安排任务在明天14:30执行
at 14:30 tomorrow
# 输入要执行的命令,按Ctrl+D结束
echo "Hello from at command" > /tmp/at_test.txt
# 按Ctrl+D结束输入

示例2:使用相对时间

# 5分钟后执行
at now + 5 minutes
echo "This will run in 5 minutes" >> /tmp/at_log.txt

# 2小时后执行
at now + 2 hours
/usr/bin/backup_script.sh

# 3天后执行
at now + 3 days
echo "Reminder: Meeting in 3 days" | mail -s "Meeting Reminder" user@example.com

示例3:使用绝对时间

# 指定具体日期和时间
at 14:30 2024-12-25
echo "Merry Christmas!" > /tmp/christmas.txt

# 使用不同日期格式
at 14:30 12/25/24
at 14:30 25.12.24

示例4:从文件读取命令

# 创建包含命令的文件
cat > /tmp/commands.txt << 'EOF'
echo "Starting backup at $(date)" >> /var/log/backup.log
/usr/local/bin/backup.sh
echo "Backup completed at $(date)" >> /var/log/backup.log
EOF

# 从文件读取命令并在指定时间执行
at -f /tmp/commands.txt 02:00 tomorrow

示例5:使用管道

# 通过管道传递命令
echo "echo 'Hello from at'" | at now + 1 minute

# 多行命令
cat << 'EOF' | at 15:00
echo "Task started"
sleep 10
echo "Task completed"
EOF

示例6:查看和管理任务

# 查看所有待执行任务
atq
# 或
at -l

# 查看任务的详细内容
at -c 任务号

# 删除任务
atrm 任务号
# 或
at -d 任务号

# 删除所有任务(小心使用)
atq | awk '{print $1}' | xargs atrm

示例7:邮件通知

# 任务完成后发送邮件(无论是否有输出)
at -m 14:30 tomorrow
echo "This task will send mail"

# 仅当有输出时才发送邮件
at -M 14:30 tomorrow
echo "This will generate output and send mail"
echo "Another line of output"

示例8:使用不同队列

# 指定队列b
at -q b 15:00
echo "This job is in queue b"

# 查看特定队列的任务
atq -q b
# 或
at -l -q b

# 删除特定队列的所有任务
atq -q b | awk '{print $1}' | xargs atrm

七、at命令队列系统

at 命令使用队列系统来管理任务,支持26个队列(a-z)和26个扩展队列(A-Z):

队列 说明 默认配置
a 默认队列 普通任务
b 批处理队列 在系统负载低时运行
c 队列c 可自定义用途
= 当前运行的任务 运行中显示
A-Z 扩展队列 需要配置

at命令输出示例

$ atq
8   2024-12-25 14:30 a username
9   2024-12-31 23:59 b username
10  2025-01-01 00:00 c username

输出字段说明:

  • 任务号:任务的唯一标识符
  • 执行时间:任务计划执行的时间
  • 队列:任务所属的队列
  • 用户名:创建任务的用户

八、实用技巧

1. 复杂任务调度

#!/bin/bash
# 安排一个复杂的备份任务
BACKUP_TIME="02:00"
BACKUP_DATE="tomorrow"

cat << 'EOF' | at $BACKUP_TIME $BACKUP_DATE
#!/bin/bash
LOG_FILE="/var/log/backup_$(date +%Y%m%d).log"
echo "=== 备份开始: $(date) ===" >> "$LOG_FILE"

# 备份数据库
mysqldump -u root --all-databases > /backup/db_$(date +%Y%m%d).sql 2>> "$LOG_FILE"

# 备份网站文件
tar -czf /backup/www_$(date +%Y%m%d).tar.gz /var/www/html 2>> "$LOG_FILE"

# 删除7天前的备份
find /backup -name "*.sql" -mtime +7 -delete
find /backup -name "*.tar.gz" -mtime +7 -delete

echo "=== 备份完成: $(date) ===" >> "$LOG_FILE"
EOF

echo "备份任务已安排在 $BACKUP_DATE $BACKUP_TIME 执行"

2. 系统维护任务

# 安排系统更新(在凌晨进行)
at 03:00 sunday
sudo apt-get update && sudo apt-get upgrade -y

# 清理临时文件(每周一早上)
at 04:00 monday
find /tmp -type f -mtime +7 -delete
find /var/tmp -type f -mtime +7 -delete

3. 任务监控脚本

#!/bin/bash
# 监控at任务并发送通知
TASK_COUNT=$(atq | wc -l)
MAX_TASKS=10
ADMIN_EMAIL="admin@example.com"

if [ "$TASK_COUNT" -gt "$MAX_TASKS" ]; then
    echo "警告: 当前有 $TASK_COUNT 个at任务等待执行" | \
    mail -s "At任务过多警告" "$ADMIN_EMAIL"
fi

# 列出所有任务
echo "当前at任务列表:" > /tmp/at_tasks.txt
atq >> /tmp/at_tasks.txt

# 发送每日报告
cat /tmp/at_tasks.txt | mail -s "At任务每日报告" "$ADMIN_EMAIL"

4. 定时提醒功能

#!/bin/bash
# 创建会议提醒
REMINDER_TIME="10:00"
MEETING_TIME="14:00"

# 提前4小时提醒
at $REMINDER_TIME today << 'EOF'
MESSAGE="提醒: 下午2点有重要会议,请提前准备。"
echo "$MESSAGE" | wall
echo "$MESSAGE" | mail -s "会议提醒" $(whoami)
EOF

echo "会议提醒已安排在 $REMINDER_TIME"

5. 批量任务管理

#!/bin/bash
# 批量创建at任务
TASKS=(
    "09:00 today 'echo \"开始工作\"'"
    "13:00 today 'echo \"午休时间\"'"
    "18:00 today 'echo \"下班时间\"'"
)

for TASK in "${TASKS[@]}"; do
    TIME=$(echo "$TASK" | awk '{print $1}')
    DATE=$(echo "$TASK" | awk '{print $2}')
    CMD=$(echo "$TASK" | cut -d"'" -f2)

    echo "$CMD" | at "$TIME" "$DATE"
    echo "任务已安排: $TIME $DATE - $CMD"
done

6. 安全注意事项

# 配置at.allow和at.deny文件
# 允许特定用户使用at
echo "username1" | sudo tee -a /etc/at.allow
echo "username2" | sudo tee -a /etc/at.allow

# 禁止特定用户使用at
echo "baduser" | sudo tee -a /etc/at.deny

# 查看当前配置
sudo cat /etc/at.allow 2>/dev/null || echo "at.allow文件不存在"
sudo cat /etc/at.deny 2>/dev/null || echo "at.deny文件不存在"

九、at与cron对比

特性 at命令 cron命令
任务类型 一次性任务 周期性任务
时间灵活性 非常高,支持多种时间格式 固定时间表(分钟、小时、日、月、周)
任务管理 简单,任务执行后自动删除 复杂,需要手动管理crontab
使用场景 临时任务、一次性提醒、特定时间执行 日常维护、周期性备份、定时监控
配置方式 命令行交互或文件输入 crontab文件编辑
环境变量 继承当前shell环境 有限的环境变量
邮件通知 内置支持 需要配置
队列系统 支持多个队列 不支持队列
资源限制 较少限制 可能有资源限制

选择建议

  • 使用at的场景:需要在特定时间执行一次的任务,如系统重启提醒、会议提醒、临时备份等
  • 使用cron的场景:需要定期重复执行的任务,如每日备份、日志轮转、定时监控等
  • 结合使用:可以先用at安排一个任务,在任务中设置cron作业

十、常见问题

Q: at命令执行后没有输出?

A: at命令默认不会在终端显示输出,输出会通过邮件发送给用户。如果需要查看输出:

  1. 检查邮件:mail
  2. 将输出重定向到文件:echo "date" > /tmp/output.txt
  3. 使用-m选项强制发送邮件
  4. 查看系统日志:journalctl -u atd
Q: at任务没有按时执行?

A: 可能原因:

  1. atd服务未运行:sudo systemctl status atd
  2. 系统时间不正确
  3. 任务被删除或修改
  4. 权限问题(检查/etc/at.allow/etc/at.deny
  5. 系统在指定时间处于关机或休眠状态
Q: 如何修改已安排的at任务?

A: at任务不支持直接修改,需要:

  1. 删除原任务:atrm 任务号
  2. 创建新任务:at 新时间
  3. 查看任务内容(用于重新创建):at -c 任务号
Q: at命令的环境变量问题

A: at任务会继承当前shell的环境变量,但某些变量可能会丢失。解决方法:

# 在at任务中明确设置环境变量
at 14:30 << 'EOF'
export PATH=/usr/local/bin:$PATH
export MY_VAR="value"
/path/to/script.sh
EOF

# 或者在脚本中设置
at -f /path/to/script.sh 14:30
Q: at任务中的路径问题

A: at任务执行时可能使用不同的工作目录和环境。建议:

  1. 使用绝对路径:/usr/local/bin/myscript.sh
  2. 在任务中设置工作目录:cd /path/to/dir && ./script.sh
  3. 在脚本开头设置环境变量
注意事项:
  • at任务执行时可能没有完整的终端环境,交互式程序可能无法正常工作
  • 确保atd服务正常运行
  • 重要任务应考虑添加错误处理和日志记录
  • 避免安排大量at任务导致系统负载过高
  • 定期检查/etc/at.allow/etc/at.deny文件权限
最佳实践:
  • 为重要任务添加日志记录和错误处理
  • 使用-f选项从文件读取复杂任务
  • 合理安排任务时间,避免系统高峰时段
  • 定期清理已完成的任务记录
  • 结合使用at和cron以满足不同的调度需求