我使用的是 Ubuntu 18.04.6 LTS,并且我有一个 cronjob,它每分钟将自动关闭命令安排到特定at
队列:
$ crontab -e
*/1 * * * * [ -z "$(w -h)" ] && echo "/sbin/shutdown -h now" | at -q w "now + 1 hour"
我现在遇到的问题是,当机器在现在和 +1 小时之间手动停止时(意味着有一个计划执行的作业),并且机器在第二天重新启动,它会立即再次关闭。
at
当系统再次启动时,似乎会执行过期的作业。当然这很烦人,所以我想,我应该在机器再次启动时删除这些作业。
我创建了一个脚本,用于从队列中删除所有作业/usr/sbin/remove_shutdown_jobs
:
#!/bin/bash
jobs=$(atq -q w | cut -f1); if [ -n "$jobs" ]; then atrm $jobs; fi;
我使它可执行:
$ ls -lah /usr/sbin/remove_shutdown_jobs
-rwxr-xr-x 1 root root 81 Aug 22 12:06 /usr/sbin/remove_shutdown_jobs
然后我尝试将其链接到rc5.d
目录并为其指定名称S00
以便执行前 atd
已启动(我的猜测是,我必须在 at 守护进程启动之前删除作业,否则它可以拾取那些旧作业并执行它们):
$ ln -s /usr/sbin/remove_shutdown_jobs /etc/rc5.d/S00remove_shutdown_jobs
$ ln -lah
lrwxrwxrwx 1 root root 30 Aug 31 13:49 S00remove_shutdown_jobs -> /usr/sbin/remove_shutdown_jobs
...
lrwxrwxrwx 1 root root 13 Jun 16 17:21 S01atd -> ../init.d/atd
...
但似乎该脚本从未被执行过。我用一个简单的 echo 脚本尝试了它,该脚本将一些文本附加到文件中,但这也没有执行。我认为rc5.d
是正确的目录,因为
$ runlevel
N 5
我也尝试将其链接到rc4.d
,rc3.d
但rc2.d
没有成功。我没有链接到它,rc1.d
因为这仅适用于某种救援系统,并且那里只有K01
文件(杀死?),对吧?
知道我错过了什么,或者我做错了什么吗?
答案1
读完字里行间后,我觉得你这里有一个 XY 问题。
如果我正确理解你的意图,问题 X 是,“我的系统运行一小时后,我希望它在最后一个用户注销后自动停止。”
由于您为问题 X 选择的解决方案,您现在遇到了问题 Y,即“每当我启动时,我的at
队列就充满了系统之前正常运行时间产生的垃圾”。
我将建议您通过使用问题 X 的更清晰的解决方案来消除问题 Y。
创建一个小脚本来检查是否有人登录,如果是,则延迟 60 秒后再检查。一旦没有人登录,就停止系统。
# cat << EOF > /root/bin/check-for-halt.sh
#!/usr/bin/env bash
# If anyone is logged in, wait sixty seconds, then check again.
while [ -n "$(w -h)" ] && sleep 60
do
:
done
# If no one is logged in, halt the system.
[ -z "$(w -h)" ] && /sbin/shutdown -h now
EOF
# chmod 700 /root/bin/check-for-halt.sh
然后将您的crontab
行替换为以下行:
@reboot root sleep 3600 && /root/bin/check-for-halt.sh
您可以调整sleep 60
和sleep 3600
值以满足您的需要。此方法无需在每次重新启动时清除队列at
。
答案2
要运行 init 脚本,您需要添加一些像这样的序言:
#!/bin/sh
### BEGIN INIT INFO
# Provides:
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start daemon at boot time
# Description: Enable service provided by daemon.
### END INIT INFO
这将为 init 子系统提供有关运行脚本的运行级别的信息。您还需要提供如何停止、如何开始等信息。
并记录cron
为
*/1 * * * * ...
会运行,但它是违反直觉的。明确的方法是:
* * * * * ...