Mid*_*lai 17 process shell-script
我对 shell 脚本相当陌生。我有一个类似于以下的脚本,
while [ true ]
do
sleep 5m
# PART X: code that executes every 5 mins
done
Run Code Online (Sandbox Code Playgroud)
在运行时 (1) 如何从外部拦截程序和 (2) 停止睡眠过程并立即执行第 X 部分?我可以为此目的使用 SIGNALS 吗?或者,还有更好的方法?
您能否指出解决此类问题的总体方向?
Sar*_*a J 21
处理时间是脚本的责任。即使这意味着/bin/sleep今天使用,它可能不会在未来使用,因此实际上并不能保证杀死它会长期有效。好吧,我想你可以做出这样的保证,但最好不要这样做。我的观点是你不应该直接从脚本外部终止睡眠,因为睡眠是一个实现细节。相反,让您的脚本捕获不同的信号,例如SIGUSR1并将其发送到您的脚本。
一个简单的例子可能看起来像
#!/usr/bin/env bash
kill_the_sleeper () {
# This probably isn't really needed here
# If we don't kill the sleep process, it'll just
# hang around in the background until it finishes on its own
# which isn't much of an issue for "sleep" in particular
# But cleaning up after ourselves is good practice, so let's
# Just in case we end up doing something more complicated in future
if [ -v sleep_pid ]; then
kill "$sleep_pid"
fi
}
trap kill_the_sleeper USR1 EXIT
while true; do
# Signals don't interrupt foreground jobs,
# but they do interrupt "wait"
# so we "sleep" as a background job
sleep 5m &
# We remember its PID so we can clean it up
sleep_pid="$!"
# Wait for the sleep to finish or someone to interrupt us
wait
# At this point, the sleep process is dead (either it finished, or we killed it)
unset sleep_pid
# PART X: code that executes every 5 mins
done
Run Code Online (Sandbox Code Playgroud)
然后,你可能会导致部分X运行到运行kill -USR1 "$pid_of_the_script"或pkill -USR1 -f my_fancy_script
这个脚本无论如何都不是完美的,但至少对于简单的情况应该是不错的。
pLu*_*umo 13
在另一个终端中,
终止sleep进程:
pkill -f "sleep 5m"
Run Code Online (Sandbox Code Playgroud)
循环将继续。
如果pkill在您的操作系统中不可用,您可以使用以下方法获取 PID:
$ ps aux | grep '[s]leep'
username 14628 0.0 0.0 8816 672 pts/19 S+ 08:33 0:00 sleep 5m
Run Code Online (Sandbox Code Playgroud)
然后运行kill PID以终止该进程(此处:)kill 14628。
这是手动杀你的好sleep,但它可能不会在脚本用于一般目的的很好的解决方案,因为它会杀死所有过程与sleep 5m在命令的任何地方。
如果您可以编辑脚本,则更安全的选择:
更改脚本以将 PID 写入文件:
pkill -f "sleep 5m"
Run Code Online (Sandbox Code Playgroud)
然后你可以运行:
kill $(< ~/.cache/myscript/sleep.PID)
Run Code Online (Sandbox Code Playgroud)
请注意,您的 PID 文件可能会被覆盖,例如被同一脚本的另一个实例覆盖,并且可能无法满足您的要求。
我喜欢@sitaram 的使用方法ionotifywait。然而,类似的事情可以使用更普遍的基础设施来完成——shellread命令(它可以在 Bash/ksh/Zsh 中采用可选的超时)和一个 FIFO。
等待循环看起来像这样:
mkfifo /tmp/myfifo
while true; do
read -t $((5*60)) <> /tmp/myfifo
date
echo "Executed every 5 minutes"
done
Run Code Online (Sandbox Code Playgroud)
只需向 FIFO 写入换行符即可提前中断读取:
echo > /tmp/myfifo
Run Code Online (Sandbox Code Playgroud)
一些注意事项:
<>而不是常规<. 在 Bash 启动之前,常规重定向将在 Bash 中阻塞(直到写入 FIFO),read因此如果从未写入 FIFO,则永远不会超时。while [ true ]表示测试字符串“true”是否为非空,如果为非空则继续while循环。但是,while true意味着运行true命令(您可能已经猜到了)总是返回 true,如果为 true,则继续 while 循环。在这种情况下,结果完全相同。但是我认为没有[ ]测试结构会更清楚。考虑while [ false ]与while false...$((5*60))是算术展开式。 300可以很容易地使用,但这有助于演示如何在命令行中轻松执行算术。| 归档时间: |
|
| 查看次数: |
2114 次 |
| 最近记录: |