22
ifconfig | grep 'inet'

is working when executed via terminal. But not via QProcess

My sample code is

QProcess p1;
p1.start("ifconfig | grep 'inet'");
p1.waitForFinished();
QString output(p1.readAllStandardOutput());
textEdit->setText(output);

Nothing is getting displayed on textedit.

but when I use just ifconfig in start of qprocess, output is getting displayed on textedit. Did I miss any trick to construct the command ifconfig | grep 'inet' , like use \' for ' and \| for |? for special characters? but I tried that as well:(

UmNyobe
  • 22,539
  • 9
  • 61
  • 90
ScarCode
  • 3,074
  • 3
  • 19
  • 32
  • you need to specify full path for ifconifg. Your application has different PATH variable then you terminal – Kamil Klimek May 22 '12 at 11:58
  • @KamilKlimek As this might be the problem for single commands, in this case the piping of commands (which isn't supported by QProcess) is the real issue. – leemes May 22 '12 at 12:00
  • Right! totaly forgot about that one – Kamil Klimek May 22 '12 at 12:02
  • If you want to get ipaddress, use the proper way: http://qt-project.org/doc/qt-4.8/qnetworkinterface.html – J-16 SDiZ May 22 '12 at 14:53
  • possible duplicate of [Qprocess messes my linux command up (i think). how to fix?](http://stackoverflow.com/questions/7597062/qprocess-messes-my-linux-command-up-i-think-how-to-fix) – J-16 SDiZ May 22 '12 at 14:56

3 Answers3

51

QProcess executes one single process. What you are trying to do is executing a shell command, not a process. The piping of commands is a feature of your shell.

There are three possible solutions:

Put the command you want to be executed as an argument to sh after -c ("command"):

QProcess sh;
sh.start("sh", QStringList() << "-c" << "ifconfig | grep inet");

sh.waitForFinished();
QByteArray output = sh.readAll();
sh.close();

Or you could write the commands as the standard input to sh:

QProcess sh;
sh.start("sh");

sh.write("ifconfig | grep inet");
sh.closeWriteChannel();

sh.waitForFinished();
QByteArray output = sh.readAll();
sh.close();

Another approach which avoids sh, is to launch two QProcesses and do the piping in your code:

QProcess ifconfig;
QProcess grep;

ifconfig.setStandardOutputProcess(&grep); // "simulates" ifconfig | grep

ifconfig.start("ifconfig");
grep.start("grep", QStringList() << "inet"); // pass arguments using QStringList

grep.waitForFinished(); // grep finishes after ifconfig does
QByteArray output = grep.readAll(); // now the output is found in the 2nd process
ifconfig.close();
grep.close();
leemes
  • 44,967
  • 21
  • 135
  • 183
  • 2
    Grep worked .But I want to pipe the output of ifconfig to awk '/inet/{gsub(/.*:/,"",$1);print$1}'. which succesfully printed some o/p on terminal and not via Qprocess. I used me thod 2 of your solution – ScarCode May 22 '12 at 12:15
  • You should prefer the 3rd method. For complicated arguments, you should pass them using a QStringList like I did in the first example. I'll update the 3rd method to give you an idea. – leemes May 22 '12 at 14:47
  • 2
    I believe the second example is wrong: if you start the shell and write to it, you also need to (1) send commands to the shell by adding newlines and (2) terminate the shell after the `grep` command executed, or `waitForFinished()` will wait forever. I did a quick test to verify if your code worked, and it didn't for me, but correct me if I am mistaken :) – AkiRoss Mar 27 '14 at 11:15
  • 2
    @AkiRoss Thank you very much for your input, you're right. (2): I guess the problem is that `sh` waits for more commands on stdin. You should close sh's stdin channel with `sh.closeWriteChannel()` between write and wait. (1): I'm 95% sure that the `\n` is not necessary. (1)+(2): If you do *not* close stdin, and do *not* write a newline, nothing seems to happen. If you do either, the command is executed, but only closing sh's stdin will shut down sh after execution. So if we solve (2), we don't need to care about (1). If we'd like to execute multiple commands, we should fix (1) but not (2). – leemes Mar 27 '14 at 12:30
  • I agree on (1) -> (2). But not sure about (2) -> (1), as I believe that '\n' is always required unless you execute the command by sending it to sh (i.e. not calling `sh -c command`). In my experience, I *had* to use the terminator, and it seems logical because sh can't normally tell when a command has been finished to be written, and it evaluates the input only when submitted with a newline. So, I believe it is required when using `sh` in this way. – AkiRoss Mar 27 '14 at 12:59
  • 1
    @AkiRoss Closing stdin will also execute what's "on the last line". Simply try it in your terminal: `echo -n 'ifconfig | grep inet' | sh`, where `echo -n` omits the line break. It will however terminate afterwards, and the pipe between echo and sh will close sh's stdin stream. – leemes Mar 27 '14 at 13:29
  • For the second solution in my case, putting "\n" after the command is sufficient instead of closeWriteChannel(). I don't want to use it because if I use it, only write() functions that work are the ones until closeWriteChannel() – atakli Sep 28 '22 at 09:32
9

The QProcess object does not automatically give you full blown shell syntax: you can not use pipes. Use a shell for this:

p1.start("/bin/sh -c \"ifconfig | grep inet\"");
kmkaplan
  • 18,655
  • 4
  • 51
  • 65
  • 1
    Ah yes, it should be double quotes, not quotes. – kmkaplan May 22 '12 at 12:11
  • 4
    alternative (safer since you don't have to pay attention to escaping within the argument, if it's more complicated): use QStringList for the arguments, like this: `p1.start("/bin/sh", QStringList() << "-c" << "ifconfig | grep inet");` – leemes May 22 '12 at 14:45
6

You can not use the pipe symbol in QProcess it seems.

However there is the setStandardOutputProcess Method that will pipe the output to the next process.

An example is provided in the API.

BergmannF
  • 9,727
  • 3
  • 37
  • 37