capture output from shell command using QProcess in Qt6
-
I'm using QProcess to run shell commands and capture the output on Linux. My program worked fine when compiled with Qt 5.15, but now it's not working with Qt 6.2.3.
Here's some example code
QString s = "ls"; QString output; process.start("sh", QStringList() << "-c" << s); process.waitForFinished(); output = QString(process.readAllStandardOutput()); output += QString(process.readAllStandardError()); WriteLog("Output: [" + output + "]"); /* my function */
The shell command always runs successfully (cp, mv, etc), but I can no longer capture the output. I do want to run the command synchronously, meaning I want to wait until the command has finished before moving on, if that makes a difference now. Has something changed in Qt6 with output? Is there a new way to capture output?
-
I'm using QProcess to run shell commands and capture the output on Linux. My program worked fine when compiled with Qt 5.15, but now it's not working with Qt 6.2.3.
Here's some example code
QString s = "ls"; QString output; process.start("sh", QStringList() << "-c" << s); process.waitForFinished(); output = QString(process.readAllStandardOutput()); output += QString(process.readAllStandardError()); WriteLog("Output: [" + output + "]"); /* my function */
The shell command always runs successfully (cp, mv, etc), but I can no longer capture the output. I do want to run the command synchronously, meaning I want to wait until the command has finished before moving on, if that makes a difference now. Has something changed in Qt6 with output? Is there a new way to capture output?
@GregB said in capture output from shell command using QProcess in Qt6:
My program worked fine when compiled with Qt 5.15, but now it's not working with Qt 6.2.3.
This sounds depressing! Out of interest, you have no need of
sh -c
to run anls
, what happens if you run thels
(or/bin/ls
to be sure) without thesh -c
?Also, if I wanted to test I might get rid of the
waitForFinished()
and thereadAll...()
and try it with signals/slots, does that work? -
In addition to what @JonB wrote, I wonder if your Qt6 version has the fix for this QProcess security issue applied whereas your Qt5.15 version does not.
-
@JonB I was using
ls
as an example here. Most of the commands I'm running are big long things that run other commands and pass lots of parameters and paths, and sometimes sequences of commands separated by semi-colons. So in the end,sh -c "FSL_DIR=/usr/local/fsl; source ${FSL_DIR}/setpaths.sh; program -o parameter; more commands; etc"
was best.
Running the command using QProcess isn't the issue, that works just fine. It executes, and returns just fine. But I can't capture the output like I used to.I'm wondering if it's a library issue, since i'm building on CentOS 8, or that QProcess in Qt6 doesn't quite work the same way as Qt5.15.
How would one use signals/slots in a program that is not asynchronous?
-
@JonB I was using
ls
as an example here. Most of the commands I'm running are big long things that run other commands and pass lots of parameters and paths, and sometimes sequences of commands separated by semi-colons. So in the end,sh -c "FSL_DIR=/usr/local/fsl; source ${FSL_DIR}/setpaths.sh; program -o parameter; more commands; etc"
was best.
Running the command using QProcess isn't the issue, that works just fine. It executes, and returns just fine. But I can't capture the output like I used to.I'm wondering if it's a library issue, since i'm building on CentOS 8, or that QProcess in Qt6 doesn't quite work the same way as Qt5.15.
How would one use signals/slots in a program that is not asynchronous?
@GregB
I know your desired commands are complex.
I suggested you might like to verify whether the same behaviour is observed in a simple command.
I suggested you might like to see if the signal/slot calls (e..greadyRead...
) work instead of your current code.
Up to you. -
@GregB
I know your desired commands are complex.
I suggested you might like to verify whether the same behaviour is observed in a simple command.
I suggested you might like to see if the signal/slot calls (e..greadyRead...
) work instead of your current code.
Up to you. -
Thanks @JonB . I tried the
/bin/sh
but that didn't work. It still runs the commands just fine, but doesn't capture the output.How would I use signals/slots with this?
@GregB
If you read what I wrote I suggested you try the simplest command, e.g. a direct/bin/ls
, no arguments, no/bin/sh
. We are trying to eliminatesh
from the issue equation.For signals/slots: get rid of
waitForFinished()
, get rid ofreadAll...()
, attach slots to the tworeadyRead...()
signals, see if those receive any output. -
Also, what is the output you are getting now? Can you check what the stdout/stderr out is directly without using your WriteLog function? Not as a solution, but just to help debug your issue, you can try setting QProcess::setStandardOutputFile() and see what gets written to that file. Note, as the documentation says,
readAllStandardOutput()
will no longer work when you use this. -
I'm using QProcess to run shell commands and capture the output on Linux. My program worked fine when compiled with Qt 5.15, but now it's not working with Qt 6.2.3.
Here's some example code
QString s = "ls"; QString output; process.start("sh", QStringList() << "-c" << s); process.waitForFinished(); output = QString(process.readAllStandardOutput()); output += QString(process.readAllStandardError()); WriteLog("Output: [" + output + "]"); /* my function */
The shell command always runs successfully (cp, mv, etc), but I can no longer capture the output. I do want to run the command synchronously, meaning I want to wait until the command has finished before moving on, if that makes a difference now. Has something changed in Qt6 with output? Is there a new way to capture output?
@GregB I just wrote (Qt 6.2.3) similar code to capture output of
which
(I needed to locate ssh client).
This worked for me (simplified and version in progress, my shell is zsh):QProcess check; check.start("zsh",QStringList({"-c","which ssh"})); if (!check.waitForStarted()) { QMessageBox::warning(this,"Warning","Could not run detection routine, you have to specify SSH runtime manually"); qDebug() << check.errorString(); } else { check.waitForReadyRead(); qDebug() << check.readAllStandardOutput(); check.write("exit"); check.waitForFinished(); }
If you worry about capturing errors you can avoid double checking of error channel by issuing
QProcess::setProcessChannelMode(QProcess::MergedChannels);
As for the why the way you did it stopped to work I have no answer though.
-
@artwaw Thanks for testing that bit of code. I figured out the issue and it appears to be a bug in Qt6. I eventually got my code to work, but only on a different OS. I tested the following combinations:
CentOS 8 + Qt 5.15 --> works correctly
CentOS Stream 8 + Qt 5.15 --> works correctly
CentOS Stream 8 + Qt 6.2 --> doesn't work (this is my current production platform)
Rocky Linux 8 + Qt 6.2 --> works correctlyI reported the bug to Qt. It's a weird bug and one that was only noticed after a few weeks. Unfortunately my production server is CentOS Stream 8, and I can't revert to a previous version of my program. So the best course is to upgrade the production server to Rocky Linux 8. That'll fix the issue for me :-)
Thank you all for your help!
-
@GregB
IMHO it's a shame you did not try either of the suggestion I made in earlier post:@JonB said in capture output from shell command using QProcess in Qt6:
@GregB
If you read what I wrote I suggested you try the simplest command, e.g. a direct /bin/ls, no arguments, no /bin/sh. We are trying to eliminate sh from the issue equation.
For signals/slots: get rid of waitForFinished(), get rid of readAll...(), attach slots to the two readyRead...() signals, see if those receive any output.Doing so would tell us/you whether (a) it has anything to do with shell or not and (b) whether it has anything to do with the
waitFor...()
calls or not. It may well be that your issue still occurs, but al least we would know.