最近学习了at
Unix系统中的命令。
假设我想要一个 Python 脚本(可能会崩溃)在启动它 2 小时后运行。我会这样做:
$ echo python3 my_script.py | at now + 2hours
我有几个问题:
- 这是正确的做法吗?
- 我如何捕获任何日志?因为如果脚本失败,
at
不会通知我,而且我无法访问错误。 - 我确实想使用它,
at
因为它让我的生活变得轻松很多,但它真的能做到这一点吗?我应该使用其他工具吗?
答案1
这是正确的做法吗?
是的,基本上at
是正确的工具,即使你退出后它也可以工作。
我如何才能捕获任何日志?
这POSIX 规范at
状态[强调我的]:
-m
at-job 运行完毕后,向调用用户发送邮件,宣布其完成。除非重定向到其他地方,否则 at-job 产生的标准输出和标准错误也应通过邮件发送给用户。即使作业没有产生任何输出,也应发送邮件。
如果
-m
未使用,则应通过邮件的方式向用户提供作业的标准输出和标准错误,除非它们被重定向到其他地方;如果没有这样的输出可提供,则实现不需要通知用户作业已完成。
确保您能够收到邮件,然后在时间到时检查邮件;或者重定向。
(“时间到了”的意思是“作业完成后”。根据您要运行的内容,您可能能够或不能提前知道需要多长时间。您的at
when 调用at -l
可能会(也可能不会)显示当前正在运行的作业。请阅读man 1 at
。)
at
使用“单独调用 shell”。您通过管道传送的命令at
将被解释为 shell 代码。这意味着您可以在那里指定重定向。示例:
echo 'python3 my_script.py >>/path/to/log 2>&1' | at now + 2hours
另一个示例,这个示例记录实际命令之前和之后的时间戳,并使用此处的文档而不是echo
:
at now + 2hours <<EOF
{
echo start
date
python3 my_script.py
echo "$?"
date
echo finish
} >/path/to/log 2>&1
EOF
注意,如果重定向失败,则会向您发送一条说明此事实的错误消息(并且{ }
不会执行其中的 shell 代码);因此,无论如何,接收和检查邮件都是有益的。
如果脚本失败,
at
不通知我
一般来说,这不是“如果作业失败”。at
如果您不使用-m
并且作业没有向 stdout(未重定向)和 stderr(未重定向)打印任何内容,则不会尝试通过邮件通知您。作业保持沉默才是最重要的,作业的退出状态无关紧要。
此外,没有报告该作业的退出状态(至少在我的 Debian 中)。
在上面的例子中,我包含了echo "$?"
。这是获取 的退出状态的方法python3 my_script.py
。
它
at
真的是要这么做吗?
是的,这种行为是设计使然。您可以称其为非最佳设计,但请注意,每个作业都在单独的进程组中运行,没有控制终端,因此即使您注销后它也可以工作;这有时是一个巨大的优势。邮件是联系当前可能已注销的用户的好方法。
尽管如此,因为你给予外壳代码到at
,您可以轻松传递多个命令并使用重定向,从而完全自定义在哪里打印什么,而不依赖邮件(在错误重定向的情况下邮件仍然有用)。
我应该使用其他工具吗?
这取决于你。在我看来,可能没有必要。at
是一个完善的标准工具。也许存在一些限制,at
这可能是想要一个更好的工具的理由,但所讨论的问题不应被视为其中之一,因为它可以轻松解决,如上所示。
此外,在 *nix 中,还有自定义命令的常规方法。例如:
alias at='at -m'
会自动添加-m
到at
shell 中的命令。这样,您就可以at
无条件地强制发送邮件,而无需-m
每次都输入内容。这个 shell 函数:
atl () ( (printf "exec >'%s' 2>&1\n" "$LOG"; cat) | at "$@" )
将允许您执行以下操作:
echo python3 my_script.py | LOG=/path/to/log atl now + 2hours
上述函数是概念证明,它可能不安全。如果扩展
$LOG
包含单引号,则会出现错误。如果的值$LOG
不完全受您控制,则可以执行不想要的(甚至是恶意的)代码。要轻松修复,请使用%q
而不是'%s'
;xor(在 Bash 中)使用%s
而不是'%s'
and "${LOG@Q}"instead of
"$LOG"`。但是这些方法不可移植。其他 shell 可能会为您提供类似的可能性。修改后的函数应该可以在 Bash 中工作:atl () { (printf "exec >%s 2>&1\n" "${LOG@Q}"; cat) | at "$@" }
有了这些知识,请自己回答“我应该使用其他工具吗?”。