at 命令是一个用于安排一次性任务的命令行工具。与 cron 不同,cron 用于周期性的重复任务,而 at 用于只在特定时间运行一次的任务。at 命令非常灵活,支持多种时间格式和相对时间表示。
在大多数 Linux 发行版中,at 命令需要单独安装:
sudo apt-get install at
sudo yum install at
# CentOS 8+使用dnf
sudo dnf install at
sudo dnf install at
sudo pacman -S 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 命令支持非常灵活的时间格式,包括绝对时间和相对时间:
| 格式 | 示例 | 说明 |
|---|---|---|
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) |
| 格式 | 示例 | 说明 |
|---|---|---|
now + 时间单位 |
now + 5 minutes |
5分钟后 |
明天 + 时间 |
tomorrow 14:30 |
明天14:30 |
下周 + 时间 |
next week |
下周的同一时间 |
下月 + 时间 |
next month |
下月的同一时间 |
明年 + 时间 |
next year |
明年的同一时间 |
支持的时间单位:minutes(分钟)、hours(小时)、days(天)、weeks(周)、months(月)、years(年)。
# 安排任务在明天14:30执行
at 14:30 tomorrow
# 输入要执行的命令,按Ctrl+D结束
echo "Hello from at command" > /tmp/at_test.txt
# 按Ctrl+D结束输入
# 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
# 指定具体日期和时间
at 14:30 2024-12-25
echo "Merry Christmas!" > /tmp/christmas.txt
# 使用不同日期格式
at 14:30 12/25/24
at 14:30 25.12.24
# 创建包含命令的文件
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
# 通过管道传递命令
echo "echo 'Hello from at'" | at now + 1 minute
# 多行命令
cat << 'EOF' | at 15:00
echo "Task started"
sleep 10
echo "Task completed"
EOF
# 查看所有待执行任务
atq
# 或
at -l
# 查看任务的详细内容
at -c 任务号
# 删除任务
atrm 任务号
# 或
at -d 任务号
# 删除所有任务(小心使用)
atq | awk '{print $1}' | xargs atrm
# 任务完成后发送邮件(无论是否有输出)
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"
# 指定队列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 命令使用队列系统来管理任务,支持26个队列(a-z)和26个扩展队列(A-Z):
| 队列 | 说明 | 默认配置 |
|---|---|---|
a |
默认队列 | 普通任务 |
b |
批处理队列 | 在系统负载低时运行 |
c |
队列c | 可自定义用途 |
= |
当前运行的任务 | 运行中显示 |
A-Z |
扩展队列 | 需要配置 |
$ 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
输出字段说明:
#!/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 执行"
# 安排系统更新(在凌晨进行)
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
#!/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"
#!/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"
#!/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
# 配置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命令 |
|---|---|---|
| 任务类型 | 一次性任务 | 周期性任务 |
| 时间灵活性 | 非常高,支持多种时间格式 | 固定时间表(分钟、小时、日、月、周) |
| 任务管理 | 简单,任务执行后自动删除 | 复杂,需要手动管理crontab |
| 使用场景 | 临时任务、一次性提醒、特定时间执行 | 日常维护、周期性备份、定时监控 |
| 配置方式 | 命令行交互或文件输入 | crontab文件编辑 |
| 环境变量 | 继承当前shell环境 | 有限的环境变量 |
| 邮件通知 | 内置支持 | 需要配置 |
| 队列系统 | 支持多个队列 | 不支持队列 |
| 资源限制 | 较少限制 | 可能有资源限制 |
A: at命令默认不会在终端显示输出,输出会通过邮件发送给用户。如果需要查看输出:
mailecho "date" > /tmp/output.txt-m选项强制发送邮件journalctl -u atdA: 可能原因:
sudo systemctl status atd/etc/at.allow和/etc/at.deny)A: at任务不支持直接修改,需要:
atrm 任务号at 新时间at -c 任务号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
A: at任务执行时可能使用不同的工作目录和环境。建议:
/usr/local/bin/myscript.shcd /path/to/dir && ./script.sh/etc/at.allow和/etc/at.deny文件权限-f选项从文件读取复杂任务