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