有些应用程序不会完全退出,留下其进程。我发现的一个例子是福昕阅读器。当然,理想的情况是报告错误并修复应用程序,但有时这是不可能的。例如,对于福昕阅读器,开发人员表示他们不再对当前版本进行任何修复,因为他们正在进行完全重写。
我希望这样当我退出应用程序时,它留下的进程会自动关闭(当然不会创建更多留下的进程)。我怎么做?
答案1
我相信最简单的方法是通过脚本启动程序并建立trap
整个kill
进程组:
#!/bin/bash
trap "kill -9 -- -$$" ERR EXIT
/path/to/gui-programm
它是如何工作的?
Atrap
是一个 shell 内置命令,如果脚本收到一个(或多个)信号,它就会执行特定命令。在这种情况下,EXIT 代表正常退出(即关闭 GUI 程序),ERR 代表任何错误(例如CTRL+C,或者 Foxit 被其他原因杀死)。参考:man signal
和man bash
使用的命令是kill
,其中-9
发送 SIGKILL。kill
可以通过向 PID 添加减号来终止单个进程,从而kill <pid>
作用于整个进程组(即进程及其所有子进程和分支)。--
需要这样,以便以下参数不会被解释为标志。即kill -9 -- -$pid
会杀掉一段时间的进程组。
$$
只是当前 shell 脚本的 PID。 GUI程序是脚本的子进程,并且GUI程序本身的子进程也是链接到作为源的脚本的进程组的一部分。
如果你想测试它,我建议使用多次睡眠:
#!/bin/bash
#test script for kill via trap
trap "kill -9 -- -$$" ERR EXIT
for (( i=1 ; i<=100 ; i++ )) ; do
sleep 120
done
/path/to/gui-command
现在,如果退出 GUI 命令,所有睡眠都会消失。如果您注释掉陷阱部分,它们将保留下来。
为了确保trap
在子进程失败时也执行 ,需要通过 继承set -E
。
#!/bin/bash
set -E
trap "kill -9 -- -$$" ERR EXIT
/path/to/gui-programm
答案2
一种方法是从脚本启动应用程序,而不是直接启动应用程序。应用程序运行时其输出通过管道传输到临时文件。然后,针对该文件通过管道运行 tail 到 fifo。接下来 grep 针对 fifo 运行。当找到某些文本时,尾部进程被杀死,fifo关闭,应用程序进程被强制杀死并删除临时文件。
应选择文本,使其成为应用程序退出时输出的最后一个文本(如果从命令行启动应用程序,您可以看到该文本)。例如,当我关闭 FoxitReader 时,它输出的最后一个文本是“CJS_Module::ExitEnumJSPlugThread”。
以下示例脚本展示了它如何与 FoxitReader 配合使用,并且可以轻松适应其他应用程序:
#!/bin/bash
file=/tmp/foxit.txt
YOURPATH/foxitsoftware/foxitreader/FoxitReader "$@" &> $file &
foxitpid=$!
fifo=/tmp/tmpfifo.$$
mkfifo $fifo || exit 1
tail -f $file >$fifo &
tailpid=$!
grep -m 1 "CJS_Module::ExitEnumJSPlugThread" $fifo
kill $tailpid
rm $fifo
kill -9 $foxitpid
rm -f $file
exit 0
答案3
根据@mcarans的回答,您可以微调福昕阅读器安装目录下的启动脚本:
<INSTALLPATH>/foxitreader/FoxitReader.sh
将此脚本修改为(记得检查 <INSTALLPATH>):
#!/bin/bash
selfpath="<INSTALLPATH>/foxitreader"
file=/tmp/foxit.txt
"$selfpath/FoxitReader" "$@" &> $file &
foxitpid=$!
fifo=/tmp/tmpfifo.$$
mkfifo $fifo || exit 1
tail -f $file >$fifo &
tailpid=$!
grep -m 1 "~CJS_Module()" -m 1 "CJS_Module::ExitEnumJSPlugThread()" $fifo
kill $tailpid
rm $fifo
kill -9 $foxitpid
rm -f $file
exit 0
保存它,一切就都准备好了。您可以像往常一样双击PDF文件并将其关闭,并且不会有任何剩余进程。