7

I am writing an application that needs to open another process and get its output. Everywhere I've read online says I have to use popen and read from the file.

But I can't read from it. The output of the command gets outputted into the console window of the calling application. Below is the code I am using. I added some prints to debug.

#include <string>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <array>

int main()
{
    // some command that fails to execute properly.
    std::string command("ls afskfksakfafkas");

    std::array<char, 128> buffer;
    std::string result;

    std::cout << "Opening reading pipe" << std::endl;
    FILE* pipe = popen(command.c_str(), "r");
    if (!pipe)
    {
        std::cerr << "Couldn't start command." << std::endl;
        return 0;
    }
    while (fgets(buffer.data(), 128, pipe) != NULL) {
        std::cout << "Reading..." << std::endl;
        result += buffer.data();
    }
    auto returnCode = pclose(pipe);

    std::cout << result << std::endl;
    std::cout << returnCode << std::endl;

    return 0;
}

Reading is never actually printed to my cout and result is an empty string. I clearly see the output of the command in my terminal. If the command exits gracefully the behaviour is as expected. But I only capture the output for error cases.

Yun
  • 3,056
  • 6
  • 9
  • 28
  • Using `feof()` to control a loop is bad practice, and is pointless in your case since `fgets()` returns `NULL` on end of file. Try providing an [mcve] that people can use to recreate your problem. If you don't know what the problem is, then providing partial information like you have is a good way to leave out critical information. It is quite possible the command you are running is using a means of output that isn't redirectable using your technique. – Peter Jun 18 '17 at 01:55
  • @Peter Provided full example. I literally just added int main and added a hardcoded command... –  Jun 18 '17 at 02:08

2 Answers2

11

Popen doesn't capture stderr only stdout. Redirecting stderr to stdout fixes the issue.

#include <string>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <array>

int main()
{
    std::string command("ls afskfksakfafkas 2>&1");

    std::array<char, 128> buffer;
    std::string result;

    std::cout << "Opening reading pipe" << std::endl;
    FILE* pipe = popen(command.c_str(), "r");
    if (!pipe)
    {
        std::cerr << "Couldn't start command." << std::endl;
        return 0;
    }
    while (fgets(buffer.data(), 128, pipe) != NULL) {
        std::cout << "Reading..." << std::endl;
        result += buffer.data();
    }
    auto returnCode = pclose(pipe);

    std::cout << result << std::endl;
    std::cout << returnCode << std::endl;

    return 0;
}
7

You have to add "2>&1" at the end of command string

command.append(" 2>&1");

there is a full example https://www.jeremymorgan.com/tutorials/c-programming/how-to-capture-the-output-of-a-linux-command-in-c/

Антон М
  • 71
  • 1
  • 3