Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QProcess not sending information back after it completes



  • QString prog = "/bin/bash";//shell // program run as a shell
    QStringList arguments;
    arguments <<"-c" << "ifconfig eth0 | grep ‘inet ‘ ";//| awk ‘{print $2}’ | sed ’s/addr://’";

    // grep searches for inet line awk gets the addr ip only and s/addr: removes all but the ip number
    // arguments << "ifconfig eth0 | grep ‘inet ‘ | awk ‘{print $2}’ | sed ’s/addr://’";

    QProcess* process = new QProcess(this);
    

    process->setReadChannel(QProcess::StandardOutput);
    // process->setProcessChannelMode(QProcess::ForwardedChannels);
    process->start(prog , arguments);
    process->waitForFinished(); //
    QString tmp = process->readAll();
    int exitStatus= process->exitCode();
    ui->textEdit->append(tmp +QString::number(exitStatus));

    =================================================================
    Hi the above code looks like a good candidate for getting the IP from my machine..
    I keep on getting an exitcode of 2 , and no information is read into the Qstrint tmp .
    I got the example from here , I tested the arguments in a terminal window and they work to report the ip , the only thing that doesn't seem to work is no information is coming back out of the process.. I do have network included in the .pro file. Anyone know what might be happening. The person who uploaded the original code said that it worked on his windoz machine. I am working on a linux machine ..


  • Lifetime Qt Champion

    Hi,

    Check in the terminal that your line is correct. There is at least the single quotes that are wrong (i.e. they are not single quotes but apostrophes).



  • Hi , I have tested it. I can run

    /bin/bash -c ifconfig eth0 | grep 'inet' | awk '{print $2}' | sed 's/addr://'

    and it returns with
    192.168.1.65
    127.0.0.1



  • It might work better with the other QProcess constructor that takes a string.

    OTOH what is wrong with using QNetworkInterface::addressEntries() ?



  • That sounds like a good solution to this particular situation. I still want to read Stdout from processes run from bash. I will be using other processes in the future. Might as well try getting this one to start giving me feedback .


  • Lifetime Qt Champion

    QString prog = "/bin/bash";
    QStringList arguments;
    arguments <<"-c" << "ifconfig en1 | grep 'inet ' | awk '{print $2}' | sed 's/addr://'";
    QProcess proc;
    proc.start(prog , arguments);
    proc.waitForFinished();
    qDebug() << proc.readAllStandardError() << proc.readAllStandardOutput();
    

    Works fine on OS X.

    Note that I don't allocate it on the heap, there's no need in this case. Also with your current code you have a memory leak since you don't delete your QProcess.



  • Hi , I have actually been testing out the QProcess with a couple of
    terminal programs now and am finding that I am not reading anything in from
    Stdout at all. I have send back some modified code. I changed it to test some
    other commands that have output to the terminal window .( The sudo -i
    command gives superuser level access from that point onward. )
    I am running a debian variant of Linux on this system.

    QString prog;
    QStringList arguments;
    QProcess proc;
    QString tmp;
    int exitStatus;
    prog="sudo ";
    arguments <<"-i";
    proc.start(prog , arguments);
    proc.waitForFinished();
    tmp = proc.readAllStandardError() + proc.readAllStandardOutput();
    exitStatus= proc.exitCode();
    ui->textEdit->append(tmp +QString::number(exitStatus));
    prog="sudo ";
    arguments <<"blkid";
    proc.start(prog , arguments);
    proc.waitForFinished();
    tmp = proc.readAllStandardError() + proc.readAllStandardOutput();
    exitStatus= proc.exitCode();
    ui->textEdit->append(tmp +QString::number(exitStatus));

    The Results of running the code:
    0
    0
    grep: ‘: No such file or directory
    2

    Actual desired info from the terminal output screen contents:
    $ sudo -i

    $ sudo blkid
    /dev/mmcblk0p1: SEC_TYPE="msdos" LABEL="boot" UUID="140A-14B7" TYPE="vfat"
    /dev/mmcblk0p2: UUID="f24a4949-f4b2-4cad-a780-a138695079ec" TYPE="ext4"
    $ /bin/bash -c ifconfig en1 | grep 'inet '
    inet addr:192.168.1.65 Bcast:192.168.1.255 Mask:255.255.255.0
    inet addr:127.0.0.1 Mask:255.0.0.0



  • Ok , now here is something about my keyboard layout . I have two sets of single quotes ' ' that come up when I click the single quote symbol . I am sure it's due to the limited O/S choices of keyboard layout that I seem to have this setup. Anyhow , I needed the single quotes that stick straight up in the arguments . Not the ones that are the reverse of these ` . Well , I just noticed that one now. I had fixed up the layout so most of the symbols worked correctly . I didn't notice this little anomily. Anyhow with the proper syntax . The following code all works properly. I think I feel more comfortable with the QProcess object now . So thanks again everyone !!!

    QString prog;
    QStringList arguments;
    QProcess proc;
    QString tmp;
    int exitStatus;
    prog="sudo ";
    arguments <<"-i";
    proc.start(prog , arguments);
    proc.waitForFinished();
    tmp = proc.readAllStandardError() + proc.readAllStandardOutput();
    exitStatus= proc.exitCode();
    ui->textEdit->append(tmp +QString::number(exitStatus));
    arguments.clear();
    prog="/bin/bash";
    arguments <<arguments <<"-c" << "blkid";
    proc.start(prog , arguments);
    proc.waitForFinished();
    tmp = proc.readAllStandardError() + proc.readAllStandardOutput();
    exitStatus= proc.exitCode();
    ui->textEdit->append(tmp +QString::number(exitStatus));
    arguments.clear();
    prog = "/bin/bash";
    // arguments <<"-c" << "ifconfig en1 | grep 'inet ' | awk '{print $2}' | sed 's/addr://'";
    arguments <<"-c" << "ifconfig eth0 | grep 'inet ' | awk '{print $2}' | sed 's/addr://'";
    proc.start(prog , arguments);
    proc.waitForFinished();
    tmp = proc.readAllStandardError() + proc.readAllStandardOutput();
    exitStatus= proc.exitCode();
    ui->textEdit->append(tmp +QString::number(exitStatus));



  • @SGaist said in QProcess not sending information back after it completes:

    QString prog = "/bin/bash";
    QStringList arguments;
    arguments <<"-c" << "ifconfig en1 | grep 'inet ' | awk '{print $2}' | sed 's/addr://'";
    QProcess proc;
    proc.start(prog , arguments);
    proc.waitForFinished();
    qDebug() << proc.readAllStandardError() << proc.readAllStandardOutput();
    

    Works fine on OS X.

    Note that I don't allocate it on the heap, there's no need in this case. Also with your current code you have a memory leak since you don't delete your QProcess.

    Hi!
    Trying to do the same experiment.
    But "awk: fatal: cannot open file 'sed' for reading..." message in the console.
    Command passed ok If I write this command in console directly only.


  • Lifetime Qt Champion

    Hi,

    Use QProcess::setStandardOutputProcess. Make a QProcess for each command in the chain



  • @SGaist said in QProcess not sending information back after it completes:

    Hi,

    Use QProcess::setStandardOutputProcess. Make a QProcess for each command in the chain

    Hi!
    Something like this?

    QProcess pro1, pro2, pro3, pro4;
    QString com1, com2, com3, com4;
    
    com1 = "/bin/bash -c ifconfig eth0";
    com2 = "grep 'inet'";
    com3 = "awk '{print $2}'";
    com4 = "sed 's/addr://'";
    
    pro1.setStandardOutputProcess(&pro2);
    pro2.setStandardOutputProcess(&pro3);
    pro3.setStandardOutputProcess(&pro4);
    
    pro1.start(com1);
    pro2.start(com2);
    pro3.start(com3);
    pro4.start(com4);


  • @sitesv
    If you do it this way your first command should read just:

    ifconfig eth0
    

    because you are no longer sending the whole command line to bash.

    Don't forget you will need to split each command into the executable as one argument and the remaining command line parameters as separate arguments in a list.

    And at that point you will need to drop the single quotes you still have around each argument, because those would have been interpreted by bash. So your three arguments will end up reading inet (with or without a trailing space, you have changed your mind about that in what you have typed), {print $2) and s/addr:// respectively (each as a single argument).

    By the time you do all of this, you might decide you'd rather do all three commands yourself: the grep + awk + sed are doing simple stuff you could just do yourself. You could just read the output from ifconfig eth0 as the only QProcess you create and look through the text (see https://doc.qt.io/qt-5/qprocess.html#readAllStandardOutput), which would get rid of the complications of multiple processes if you wish.



  • @JonB said in QProcess not sending information back after it completes:

    @sitesv
    If you do it this way your first command should read just:

    ifconfig eth0
    

    because you are no longer sending the whole command line to bash.

    Don't forget you will need to split each command into the executable as one argument and the remaining command line parameters as separate arguments in a list.

    And at that point you will need to drop the single quotes you still have around each argument, because those would have been interpreted by bash. So your three arguments will end up reading inet (with or without a trailing space, you have changed your mind about that in what you have typed), {print $2) and s/addr:// respectively (each as a single argument).

    By the time you do all of this, you might decide you'd rather do all three commands yourself: the grep + awk + sed are doing simple stuff you could just do yourself. You could just read the output from ifconfig eth0 as the only QProcess you create and look through the text (see https://doc.qt.io/qt-5/qprocess.html#readAllStandardOutput), which would get rid of the complications of multiple processes if you wish.

    Thank you for your answer!

    QString prog1 = "sh", prog2 = "grep", prog3 = "awk",  prog4 = "sed";
    QProcess pro1, pro2, pro3, pro4;
    pro1.setStandardOutputProcess(&pro2);
    pro2.setStandardOutputProcess(&pro3);
    pro3.setStandardOutputProcess(&pro4);
    
    pro1.start(prog1, QStringList() << "-c" << "ifconfig eth0");
    pro1.waitForFinished();
    
    pro2.start(prog2, QStringList() << "inet ");
    pro2.waitForFinished();
    
    pro3.start(prog3, QStringList() << "{print $2}");
    pro3.waitForFinished();
    
    pro4.start(prog4, QStringList() << "s/addr://");
    pro4.waitForFinished();
    
    QByteArray out1 = pro4.readAllStandardOutput();
    QList<QByteArray> list1 = out1.split('\n');
    foreach(auto str, list1){
       qDebug() << str;
    }
    

    But in the output stream only one string. In manual mode, there are three lines.
    And this code runs for about 3 sec. Too much.



  • @sitesv said in QProcess not sending information back after it completes:

    And this code runs for about 3 sec. Too much.

    Is it possible to fix this?



  • @sitesv
    Yes. In that I already told the OP to do this via reading & parsing the output from ifconfig eth0 to do what the grep/awk/sed are doing, which is not that difficult. And the waitForFinished()s take an unknown amount of extra time too, probably. Then the only time spent will be however long ifconfig eth0 takes, plus a few microseconds for reading it. If it takes any longer than that, you are doing something wrong.


Log in to reply