QProcess 附加到从脚本运行的可执行文件

Posted

技术标签:

【中文标题】QProcess 附加到从脚本运行的可执行文件【英文标题】:QProcess attach to executable ran from script 【发布时间】:2021-07-26 17:36:19 【问题描述】:

我正在使用 QtCreator,我正在尝试创建一个运行 bash 脚本的 QProcess。在该脚本内部,执行一些其他命令后,将运行一个可执行文件。

当我监控 QProcess 时,我认为当脚本完成时,即使从该脚本启动的可执行文件仍在运行,QProcess 也会显示为已停止。

有没有办法解决这个问题?以某种方式附加到从该脚本启动的可执行文件?

我正在执行的命令是:

xterm -T "Window Title" -geometry 120x24+0+20 -e \
  bash -c 'sudo -E ./executable -s 2>&1 | tee -i log_file.log' &

...并且我希望我的父进程检测 ./executable 何时完成 - 而不在发生这种情况时强制 xterm 立即退出。

【问题讨论】:

不显示细节很难说。最简单的修复(并且可以说是最好的)是将您的脚本修改为exec,无论它启动什么进程,以便该进程接管脚本预先存在的PID。这也是许多初始化系统跟踪服务可执行文件的首选方式。 谢谢,查尔斯!你能澄清一下我该怎么做吗?在 bash 脚本中,以下命令执行可执行文件。如何将其编辑为“执行”? xterm -T "窗口标题" -geometry 120x24+0+20 -e bash -c 'sudo -E ./executable -s 2>&1 | tee -i log_file.log' & 经过一番研究,似乎这就是 xterm 命令末尾的 & 的用途?所以我不确定那是什么问题。 &exec 完全相反。 exec 会告诉 shell 在同一个进程中运行某些东西。 & 告诉 shell 产生一个子进程 如果你想保持进程树尽可能浅,一个替代方案可能看起来像:exec xterm -T "Window Title" -geometry 120x24+0+20 -e bash -c 'exec > >(exec tee -i log_file.log) 2>&1; exec sudo -E ./executable -s' 【参考方案1】:

第 1 部分:检测 xterm 何时退出

这与“第 2 部分”不同,因为它不会让您的 ./executable 一次性完成,而您的 xterm 在不同的稍后时间完成。后者见下文“第 2 部分”。

最后的& 告诉shell 不要等待xterm 进程(在“后台”运行它)。不过,在这种情况下,您希望 shell 等待——但我们可以做得更好,让 shell 完全不碍事。


第 1 步:只需取出末尾的 &

这将使进程显示为正在运行,直到 xterm 退出 - 尽管要实现这一点,作为 xterm 的父进程的 bash 的副本也将运行。

xterm -T "Window Title" -geometry 120x24+0+20 -e \
  bash -c 'sudo -E ./executable -s 2>&1 | tee -i log_file.log'

第 2 步:将 bash 的父进程副本替换为 xterm进程本身

这是通过exec 关键字完成的;当您运行exec someprogram 时,shell 将在内存中替换为someprogram 的副本(与默认行为相反,运行someprogram 时将程序作为子进程启动,但除非您使用&,否则shell 会等待该子进程在继续之前退出)。

这不仅节省了一点内存,而且还意味着您发送的信号将直接发送到xterm 进程,而不是发送到它的父级 bash 副本。

exec xterm -T "Window Title" -geometry 120x24+0+20 -e \
  bash -c 'sudo -E ./executable -s 2>&1 | tee -i log_file.log'

第 3 步:将 sudotee 移出管道

虽然上面应该已经解决了您的直接流程,但它仍然留下了一个流程树,其中包含比必要更多的移动部分:您的 Qt 程序启动 xterm,xterm 启动 bash,bash 的副本产生一个管道(将自身分叉成一个每侧的父 shell 的单独副本),并将管道的一侧替换为 sudo,另一侧替换为 tee

我们可以通过使用 bash 扩展进程替换来使 tee 作为子进程运行,并将 sudo -E ./executable 替换为 exec'd,替换 bash 的副本,xterm 开始:

p>
exec xterm -T "Window Title" -geometry 120x24+0+20 -e \
  bash -c 'exec > >(exec tee -i log_file.log) 2>&1;
           exec sudo -E ./executable -s'

请注意,在exec > >(...) 2>&1 中,我们使用了不同形式的exec:当exec 仅给出重定向作为参数时,它不会关闭当前shell 并将其替换为另一个进程,而是执行那些当前 shell 本身的重定向。因此,当我们运行 exec 2>&1 时,2>&1 重定向会针对当前 shell 执行并一直保留到它退出,因此我们不需要在 ./executable 调用上放置另一个 2>&1


第 2 部分:检测 ./executable 何时退出

但是,如果您想让 xterm 保持打开状态(以便用户可以阅读日志)即使在 ./executable 完成后怎么办?

考虑:

#!/usr/bin/env bash
exec > >(tee -i log_file.log)
xterm -T "Window Title" -geometry 120x24+0+20 -e tail -n +0 -f log_file.log &
exec sudo -E ./executable -s'

这里,我们在后台运行xterm,但在前台运行sudo -E ./executable -sexec'd 替换启动它的shell),所以父进程检测sudo何时退出,而不是当xterm 退出。

【讨论】:

感谢您的精彩解释。当我运行它时,xterm 立即消失。我希望 xterm 窗口保持打开状态并显示可执行文件的输出。知道为什么会这样吗? 在可执行文件完成后立即消失,你的意思是?因此,修复的棘手之处在于让您的父进程知道可执行文件已完成,而不是让它知道 xterm 何时退出。 ...我现在正忙于工作,但是当我有机会尝试构建一个替代答案来让您跟踪 ./executable 何时完成时,它可能依赖于父 shell 等待释放锁。 我认为可执行文件实际上并未与您发送的内容一起启动。如果我在终端中尝试,终端会关闭并且什么都不会启动。如果我从前面删除 exec 并在终端中重试,则不会启动任何内容,它只会返回。我知道可执行文件可以正常工作,因为如果我这样做 ./executable 它会在终端中正常启动。 嗯。不幸的是,因为除了你之外没有人拥有./executable,这不是我可以轻易测试的。

以上是关于QProcess 附加到从脚本运行的可执行文件的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 QProcess 同时运行多个 python 脚本

QProcess 执行 python3 脚本无法正常工作

冻结后使用 QProcess 运行 Python 脚本

通过 QProcess 运行 .sh 脚本时出错

启动使用附加库的可执行程序

运行自定义可执行文件,QProcess 立即退出,退出代码为 1