使用“at”安排的命令失败,但没有给出错误

isa*_*aac 3 linux bash at

最近了解了atUnix系统中的命令。

假设我希望一个 Python 脚本(可能会崩溃)在启动后 2 小时运行。我做了这样的事情:

$ echo python3 my_script.py | at now + 2hours 
Run Code Online (Sandbox Code Playgroud)

我有几个问题:

  1. 这是正确的做法吗?
  2. 我怎样才能捕获任何日志?因为如果脚本失败,at不会通知我,而且我无权访问该错误。
  3. 我真的很想使用它,at因为它让我的生活变得更加轻松,但它真的意味着这样做吗?我应该使用其他工具吗?

Kam*_*ski 5

这是正确的做法吗?

是的,基本上。at是正确的工具,即使在您注销后它也应该可以工作


我怎样才能捕获任何日志?

POSIX 规范的at状态[强调我的]:

-m

在作业运行后向调用用户发送邮件,宣布其完成。工作中产生的标准输出和标准错误也应邮寄给用户,除非重定向到其他地方。即使作业没有产生任何输出,也应发送邮件。

如果-m不使用,则作业的标准输出和标准错误应通过邮件的方式提供给用户,除非它们被重定向到其他地方;如果没有提供此类输出,则实现无需通知用户作业已完成。

要么确保您可以收到邮件,然后在适当的时候检查邮件;或重定向。

(“当时间到来时”的意思是“作业完成后”。根据您要运行的内容,您可能会或可能无法提前知道需要多长时间。您的何时调用可能atat -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'会自动添加-matshell 中的命令中。这样您就可以强制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)

有了这些知识,请回答“我应该使用其他工具吗?” 为自己。