QProcess 无法通过 QPushButton 执行终端行命令

Posted

技术标签:

【中文标题】QProcess 无法通过 QPushButton 执行终端行命令【英文标题】:QProcess fails to execute a terminal line command via QPushButton 【发布时间】:2020-05-12 21:29:13 【问题描述】:

我试图在我的 gui 上推送 QPushButton 后立即使用 QProcess 执行命令行。 问题我的问题是.sh 可执行文件永远不会执行。

我尝试执行的脚本非常简单,报告如下:

#!/bin/bash
echo "try one two three"
rostopic echo -b LaserScan_PointCloud2_test.bag -p /scan > laserScan_test_1.csv

在激活按钮的函数下方:

filterpcdinterface.h

private slots:
    void on_executeScriptBtn_clicked();
private:
    QProcess *executeBash;

filterpcdinterface.cpp

FilterPCDInterface::FilterPCDInterface(QNode *node, QWidget *parent) :
    qnode(node), 
    QMainWindow(parent),
    ui(new Ui::FilterPCDInterface)

    ui->setupUi(this);
    executeBash = new QProcess;
    executeBash->setProcessChannelMode(QProcess::MergedChannels);
    connect(executeBash, &QProcess::readyReadStandardOutput, [this] 
    qDebug() << "This is the output from the process: ";
      on_executeScriptBtn_clicked();
    );



void FilterPCDInterface::on_executeScriptBtn_clicked()

  executeBash->waitForFinished();
  QString script("/home/emanuele/Desktop/bags/test.sh");
  executeBash->start("sh",QStringList() << script);

  if(!executeBash->waitForStarted()) //default wait time 30 sec
      qWarning() << " cannot start process ";

  int waitTime = 60000 ; //60 sec
  if (!executeBash->waitForFinished(waitTime))
           qWarning() << "timeout .. ";

  executeBash->setProcessChannelMode(QProcess::MergedChannels);
  QString str(executeBash->readAllStandardOutput());

到目前为止,我已经查阅了几篇文章,但没有一篇文章能帮助我解决问题。 我遇到了this one 和this one,我实际上是从那里得到这个想法的。

作为解释器,我尝试了"/bin/sh""sh",但它们都没有给出预期的结果。 准确地说,我尝试了这两个:

  executeBash->start("sh",QStringList() << script);

  executeBash->start("/bin/sh",QStringList() << script);

但什么也没发生。

我终于看到了this 非常有用的帖子,它实际上帮助我设置了整个按钮功能,但是到了执行脚本的时候,这次也没有任何反应。

我不确定这种奇怪的行为是否是由构造函数中的connect 函数引起的。问题还在于qDebug() 语句也永远不会到达。

official documentation 提到了使用startDetached 语句的可能性,但我不确定它是否与我想要实现的目标完全相关。 官方文档总是报告以下声明here

Unix:启动的进程将在自己的会话中运行,并像一个 守护进程。

因此我认为有一个进程会话正在工作并且可以执行但它不是。

总结:我一直在研究问题可能是什么,但我一直错过一些我看不到的东西。请指出正确的方向以帮助解决此问题,是否有人碰巧遇到同样的问题。

【问题讨论】:

你怎么知道脚本没有执行?因为标准输出为空是正常的 您好@thibsc,感谢您阅读这个问题。我知道这是因为声明 qDebug() &lt;&lt; "This is the output from the process: " 从未在终端上显示。因此文件的执行没有发生,我不知道为什么。 这可能是正常的,因为您将输出重定向到一个文件中,尝试在脚本中添加一个回显,看看是否仍然没有任何反应 好的,我试了一下并更新了问题。基本上我在 bash 文件中添加了echo "try one two three",但仍然没有任何反应 您阅读了on_executeScriptBtn_clicked() 末尾的标准输出,您打印了str var 的内容以查看它是否包含某些内容? 【参考方案1】:

试试这个:

标题:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QProcess>

QT_BEGIN_NAMESPACE
namespace Ui  class MainWindow; 
QT_END_NAMESPACE

class MainWindow : public QMainWindow

    Q_OBJECT
public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_executeScriptBtn_clicked();

private:
    Ui::MainWindow *ui;
    QProcess    * executeBash;
;
#endif // MAINWINDOW_H

来源:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)

    ui->setupUi(this);
    this->executeBash = new QProcess(this);
    this->executeBash->setProcessChannelMode(QProcess::MergedChannels);
    connect(this->executeBash, &QProcess::readyReadStandardOutput, [script = this->executeBash]()
        qDebug() << "[EXEC] DATA: " << script->readAll();
    );
    connect(this->executeBash, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
          [script = this->executeBash](int exitCode, QProcess::ExitStatus exitStatus)
        qDebug() << "[EXEC] FINISHED: " << exitCode << exitStatus;
        if(script->bytesAvailable() > 0)qDebug() << "[EXEC] buffered DATA:" << script->readAll();
    );
    connect(this->executeBash, &QProcess::errorOccurred, [script = this->executeBash](QProcess::ProcessError error)
        qDebug() << "[EXEC] error on execution: " << error << script->errorString();
    );


void MainWindow::on_executeScriptBtn_clicked()

    qDebug() << "Button clicked!"; // if you don't see this message check your SIGNAL/SLOT connections!
    //this->executeBash->execute(...) // <- will wait till script is finished and block main thread
    this->executeBash->start(QStringLiteral("/bin/sh"), QStringList() << QStringLiteral("/home/emanuele/Desktop/bags/test.sh")); //will start new process without blocking


MainWindow::~MainWindow()delete ui;

【讨论】:

非常感谢您,效果很好!不过我有一个问题,在 on_executeScriptBtn_clicked() 上,您留下了 //this-&gt;executeBash-&gt;execute(...) 评论并想知道它的用途以及我是否需要使用它?非常感谢您的宝贵时间! :) 非常感谢 @Emanuele,如果你需要等到你的脚本完成执行,然后才在你的代码中执行下一步,你可以使用 QProcess 的 execute 函数而不是 开始。执行功能将阻止您的“代码”,直到脚本完成(此时您的 GUI 将无响应)有时在控制台应用程序中很有用,但对于 GUI 应用程序,最好使用 QProcess 的 start 功能,start 将异步执行(不会阻塞您的 GUI)。如果您需要这种行为,我只是为您评论了它:)

以上是关于QProcess 无法通过 QPushButton 执行终端行命令的主要内容,如果未能解决你的问题,请参考以下文章

Qt:如何连接“DialogClass1”的 QPushButton 来杀死“Class2”中的 QProcess?

如何将 QProcess 的执行与 QProgressBar 的推进联系起来以实现非常繁重的计算循环

如何使用 Ctrl+C 输入干净地退出 QProcess?

在 Android 平台上通过 QProcess 运行 shell 命令

如何使用 QProcess 通过 Ping 检测“网络不可达”?

需要 virtenv 时如何运行 QProcess?