延迟执行速度比 1 分钟还快?

延迟执行速度比 1 分钟还快?

我正在开发一个可以通过安装新软件包来“自我升级”的程序。为了实现此目的,我使用at命令指定应在未来一分钟运行 shell 脚本,然后 shell 脚本将安装该包。我真的希望它能在未来一分钟内执行,但根据我在手册页中读到的内容,这似乎是我能做的最好的事情。有没有办法以更严格的分辨率来做到这一点?

答案1

直接启动程序并让它立即运行更新会更容易(或者如果您确实需要它,它可以休眠一些小的延迟)。

如果这是在脚本本身中(例如,bash),只需直接调用更新脚本(可能重定向输出):

update-my-thingy < /dev/null > /dev/null 2>&1

如果它在程序中,您始终可以使用 system() 调用来执行相同的操作:

system("update-my-thingy < /dev/null > /dev/null 2>&1");

答案2

分叉一个等待几秒钟的脚本。

{ sleep 5; update-my-program; } &

如果您的目标是在程序退出后立即进行升级,但不更早,请通过调用安排您的程序终止execve代替exit。系统execve调用将当前程序替换为另一个程序。在 C 中,有多种变体(execlexecp等),具体取决于您希望如何传递参数。在shell中,对应的内置是exec.

答案3

这取决于您的程序正在做什么。对于守护进程,它是通过以下方式完成的:

  • 确定可执行文件的年龄
  • 如果年龄小于程序启动时间,则可执行文件被新版本覆盖
  • 在这种情况下,等到没有工作要做(或不做)
  • exec()自行使用新的二进制文件重新启动程序

答案4

这很棘手。首先,出于预防考虑,将调用放在脚本开头的函数中,直到最后才调用它:

% killmenow() { ... }
...
% killmenow
EOF

这是确保当前脚本中的所有内容都已完全读取并复制到内存中的最佳方法。只是说。

现在我尝试回答......

POSIX 指定了jobs用于此类事物的实用程序。具体来说,我认为 、 waittrap和的组合kill是最安全的。为了让事情尽可能干净地进行,你可以使用newgrp同样,这exec在继承品质方面也非常相似,但在这种情况下可能是关键的process id

好吧,我知道这听起来很多,但毕竟没什么可看的:

% suicide() { _me="${1}" ; ( 
>> trap 'wait "${_me}" && set -- &&\
>>> eval `newgrp && exec { YOUR | CMD | HERE }`' INT &&\
>> kill -s INT "-${_me}"
>> ) & }
...
% suicide "${$}"

好的,这是工作流程:

  • 首先,我们加载并运行整个脚本,我们确信这一点,因为suicide直到最后一行我们才这样做。
  • 我们传递给suicide我们的副本,process id然后将其保存到$_me,在这种情况下我们也可以轻松地从内部获取它suicide,但我们可能会在其他地方使用它,谁知道呢。
  • 在子 shell 中,我们调用trap扫描它trapped '$cmd'并指示它监视任何INT调用的谣言。
  • kill当然一切都准备好了,我们最后一次打电话;不仅向我们kill发出,而且我们指定整个过程组都应该接收它。不要害怕 - 除非你的整个系统已经疯了 -无论如何都不能杀死任何现在不应该能够杀死的东西。另外,您也不必在的参数中指定;我只是想做到彻底。INTERRUPT SIGNAL$_me-$_my$_me$_me-killPID

好吧,但我们还没有完成,对吧?不,我们将整个命令集放在&后台子 shell 中,因此trap仍然可以挂起并可以接听我们的INT呼叫。

  • 收到它后INTtrap现在评估它'quoted argument'- 重要的是要记住该字符串中的任何内容现在才被拉出。
  • 以防万一$_me有其他一些未解决的问题需要在其他地方解决,trap请先致电wait$_me其上只会在必要时坚守阵地
  • 准备好后,我们擦掉剩余的东西env $varsset --然后开始做正事。

newgrp被设计为运行在interactive shell- 它不一定应该提供像这样干净的逃逸过程。事实上,如果您的系统group需要密码(他们不应该这样做),那么这对您不起作用并且现在就会消失。

我称这个方法为偷偷摸摸的下面,但我直接从 POSIX 指南中提取它:

的一个常见实现newgrp是当前 shell 使用exec来覆盖自身newgrp,而在更改组后又用新 shell 覆盖自身...

然后,在下一段中...

newgrp 命令仅适用于从交互式终端使用。它不提供有用的接口来支持应用程序。

所以偷偷摸摸的部分是eval,它可以非常擅长这类事情 - 例如保存和重用"$@",但另一次,也许......

  • 相反,我们间接地使用eval一条newgrp && exec语句,首先加载另一个进程,该进程只应该从交互式提示中获取下一个命令,然后我们偷偷地exec在后门中添加{ YOUR | CMD }.

此时,我们应该在干净环境中的新进程组中的新 shell 中运行新脚本,而只需等待实际需要的时间,并彻底完成整个过程。

事实上,我们是如此彻底,以至于我们可以安全地做到这一点:

...exec { wget -O - "${URL}" >"${0}" ; exec "${0}" }

相关内容