关键在于将完整的 shell 逻辑封装成自包含的可执行命令字符串交由 at 执行,而非仅用 eof 传递输入;eof(如 cat

在 at 中直接嵌入多步逻辑的脚本,关键不是“用 EOF 传递输入”,而是**把完整的 shell 逻辑封装成一段可执行的、自包含的命令字符串**,再交给 at 执行。EOF(如 cat )本身是 shell 的 here-document 语法,用于生成文本内容,它并不属于 <code>at 的输入机制,也不能被 at 直接解析为“输入流”。真正起作用的是:你把含有多步逻辑的脚本内容,通过管道或重定向喂给 at,而 at 会将其作为待执行的命令体保存并调度。
用 here-document 构建可读性强的内联脚本
这是最贴近“利用 EOF 特性”的做法——借助 cat 把多行逻辑组织成一个干净的脚本块,避免命令拼接错误和引号嵌套灾难。
- 务必使用
(单引号包裹 delimiter),防止本地变量提前展开或命令被当前 shell 解析 - 脚本体内可自由使用换行、缩进、注释、函数、条件判断、循环等完整 shell 语法
- 结尾的
EOF必须顶格、无空格,否则 here-document 不会终止
示例:
echo 'cat #!/bin/bashlog="/tmp/at-job-$(date +%s).log"
echo "[$(date)] Starting task" > "$log"
if systemctl is-active --quiet nginx; then
echo "nginx OK" >> "$log"
else
systemctl start nginx && echo "nginx started" >> "$log" || echo "nginx failed" >> "$log"
fi
df -h / | awk '"'"'/\// {print "root usage: " $5}'"'"' >> "$log"
EOF' | at now + 2 minutes
用 printf 或 echo 拼接紧凑型单行脚本(适合简单但步骤多的任务)
当逻辑不复杂、无需缩进和注释时,用 printf %q 或手动转义可保证命令安全传递,尤其适合含变量、路径、空格的场景。
-
printf %q自动转义所有特殊字符,是最稳妥的单行化方式 - 避免用裸
echo拼接含变量的命令,容易因空格或通配符出错 - 整个拼好的命令字符串就是
at将要执行的唯一指令
示例:
cmd=$(printf %q 'mkdir -p /tmp/at-run; cd /tmp/at-run; wget -q https://example.com/data.json; jq ".items | length" data.json > count.txt; echo "done" >> status.log'); echo "$cmd" | at now + 1 minute分离脚本文件 + at 调度(推荐用于复杂、需复用或调试的任务)
真正的“优雅”往往来自解耦:把逻辑写进独立脚本,赋予执行权限,再让 at 调用它。这规避了所有 here-document 边界问题、引号陷阱和调试困难。
- 脚本开头明确写
#!/bin/bash,确保解释器一致 - 用绝对路径调用脚本(如
/home/user/bin/deploy.sh),避免at执行时的 cwd 不确定性 - 可在脚本内设置
cd /tmp或export PATH=...等上下文,比在at命令里硬编码更清晰
示例:
chmod +x /opt/scripts/backup-and-clean.shecho "/opt/scripts/backup-and-clean.sh" | at 02:00 tomorrow
注意事项与避坑点
at 默认以用户家目录为工作目录,且不加载交互式 shell 配置(如 ~/.bashrc),所以环境变量、别名、PATH 都受限。
- 显式声明
PATH=/usr/local/bin:/usr/bin:/bin,或用绝对路径调用命令(如/usr/bin/jq) - 不要依赖
~,统一用$HOME或绝对路径 - 输出重定向到文件(如
>/tmp/at-out.log 2>&1),否则 stdout/stderr 会发邮件(若 mail 服务启用) -
at任务默认以提交用户身份运行,无需 sudo;如需 root 权限,应由管理员提前配置/etc/at.allow并确保用户在其中











