0

I am trying to execute a command line using QProcess as soon as I push a QPushButton on my gui. The problem I have is that the .sh executable file is never executed.

The script I am trying to execute is very simple and reported below:

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

Below the function that activate the button:

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());
}

So far I have been consulting several posts but none of them helpd me solve the problem. I came across this one and also this one from which I actually got the idea.

As interpreter I tried both "/bin/sh" and "sh" but none of them gave the expected result. To be precise I tried both this one:

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

and

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

But nothing happened.

I finally came across this very useful post which actually helped me set up the whole button function, but when it was time to execute the script nothing happens this time too.

I am not sure if this strange behavior is caused by the connect function in the constructor. The problem is also that the qDebug() statement is also never reached.

The official documentation mention the possibility to use a startDetached statement but I am not sure it can fully relate to what I am trying to achieve. Always the official documentation reports the following statement here

Unix: The started process will run in its own session and act like a daemon.

And therefore I thought that there was a process session working and that could be executed but it is not.

In conclusion: I have been researching a lot what the problem might be but I keep missing something I don't see. Please point to the right direction to help solving this issue is anyone happened to have the same problem.

Emanuele
  • 2,194
  • 6
  • 32
  • 71
  • How do you know that the script is not executed ? Because it is normal if the standard output is empty – thibsc May 12 '20 at 21:33
  • Hello @thibsc and thanks for reading the question. I know it because the statement `qDebug() << "This is the output from the process: "` is never shown on terminal. Therefore the execution of the file does not happen, and I don't know why. – Emanuele May 12 '20 at 21:35
  • Maybe it is normal because you redirect the ouput in a file, try to just put an echo in your script and see if it still nothing happen – thibsc May 12 '20 at 21:38
  • Ok, I tried it and updated the question. Basically I added `echo "try one two three"` on the bash file but still nothing happens – Emanuele May 12 '20 at 21:44
  • You read the standard output at the end of your `on_executeScriptBtn_clicked()` you print the content of your `str` var to see if it contains something ? – thibsc May 12 '20 at 22:01
  • Recommend moving the `executeBash->setProcessChannelMode` into the constructor right after the instance of `executeBash` is created (if you do want to see `stderr`). The 1st time `on_executeScriptBtn_clicked` is called, the channels are _not_ merged so stderr won't be picked up by `QProcess::readyReadStandardOutput`. – Linville May 12 '20 at 22:13
  • @thibsc, print ing the `str` at the end of the statement I didnt try. However I have a small problem, I can't `return str` because the function is `void FilterPCDInterface::on_executeScriptBtn_clicked()`, how can I bypass this problem and try your suggestion? – Emanuele May 12 '20 at 23:38
  • Do not use designer to create your slot, make the connections by yourself. With your own slot you can do what you want. And just use `qDebug()` to see the content. And take in consideration what Linville said – thibsc May 12 '20 at 23:45
  • Guys something is happening. I implemented @Linville and got [this](https://i.imgur.com/SdXhZb0.png), however the `.sh` file is still not executed. I updated the code in the question. – Emanuele May 12 '20 at 23:48
  • Do you see something I don't see? – Emanuele May 12 '20 at 23:53
  • Remove your 2 last line of your `on_executeScriptBtn_clicked()` – thibsc May 13 '20 at 00:37

1 Answers1

1

Try this:

header:

#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

source:

#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;}
Xplatforms
  • 2,102
  • 17
  • 26
  • Perfect thank you very much that works great! I have a question though, on the `on_executeScriptBtn_clicked()` you left `//this->executeBash->execute(...)` commented and was wondering its use and if I need to use it? Thank you very much for your time! :) Very much appreciated – Emanuele May 13 '20 at 20:10
  • @Emanuele, if you need to wait till your script is finished execution and only then execute next steps in your code you could use **execute** function of QProcess instead of **start**. execute function will block your "code" until the script is finished(your GUI will be unresponsive in this time) sometimes usefull in console apps, but for GUI apps better to use **start** function of QProcess, **start** will execute asynchronous(not blocking your GUI). I just commented it for you if you need this kind of behavior :) – Xplatforms May 18 '20 at 06:16