首页 > 解决方案 > 在脚本中使用管道时,如何帮助用户避免失控进程?

问题描述

这是一个示例 bash 脚本,用于显示文件的更新。

#!/usr/bin/env bash
inotifywait -m file1.txt | while read -r line; do
    echo line
done

如果我将此脚本另存为showme.h然后在提示符下执行它,我最终会得到 3 个进程:

username 14652  9811  0 16:53 pts/2    00:00:00 bash ./showme.sh
username 14653 14652  0 16:53 pts/2    00:00:00 inotifywait -m file1.txt
username 14654 14652  0 16:53 pts/2    00:00:00 bash ./showme.sh

如果我通过 ctrl-c 结束初始进程,所有 3 个进程都会死掉。但是,如果我杀死一个单独的进程,只有那个进程会死掉,除非我通过 -pid 杀死整个进程组。

由于我打算将此脚本分发给其他人使用,因此我想让其他人易于管理。有 3 个不同的进程浮动是很麻烦的。就此而言,用户可能会发现showme.sh通过 运行的进程pgrep,但永远不会发现它inotifywait仍然存在,因此无法杀死它。当然,直接杀死进程组的用户不应该有这个问题,但用户并不总是正确地做事。

我的问题:有没有更好的方法可以让结束这个过程更加万无一失,以减少不知情的用户最终出现失控过程的可能性?一种允许我重组上述脚本的解决方案,以便只有一个过程结果是完美的,但我怀疑这通常是不可能的。我应该以一种完全不同的方式思考这个问题,我也很想听听。

(是的,我知道特别是在 inotifywait 情况下,我可以通过不将它作为监视器运行并在循环中每次都重新启动它来做到这一点,但这可能会错过一些更新。无论如何,我想知道更一般的答案是如果有的话。)

标签: linuxbash

解决方案


流程树值得一看:

  1. bash(顶级脚本)
  2. inotifywait(管道,第 1 部分)
  3. bash(管道,第 2 部分,读取/回显循环)

终止规则:

  • 任务 #1 将在任务 #3 终止时终止(这取决于任务 #2)
  • 任务 #2 将在任务 #3 终止时终止,并且当它有东西要写时(它会得到 EPIPE)
  • 任务 #3 将在任务 #2 终止时终止,这将使用 EOF 关闭输入管道

建议的解决方案是在 2 个 bash 实例中捕获“退出”条件,并终止 inotifywait 进程,这将允许整个管道正常退出。

function cleanup {
        [ -s "$PID_FILE" ] && kill $(<$PID_FILE)
        rm -f $PID_FILE
}

PID_FILE=pid.file
echo > $PID_FILE
trap 'cleanup' EXIT
( echo $BASHPID > $PID_FILE  && exec inotifywait -m file1.txt) |
        { trap 'cleanup' EXIT ; while read x ; do echo "$x" ; done }
rm -f $PID_FILE

另一种选择是在所有可能的用户信号上设置特定的陷阱。但是,从 OP 输入来看,用户并不注意遵守规则,因此很难为所有可能的组合定义信号处理程序。


推荐阅读