C++ System() Function - How to Collect the Output of the Issued Command

C++ system() function — How to collect the output of the issued command?

Are you looking for returned value (as in "exit status") of the executed command, or for its output (as in "what did it print")?

If the latter, use popen() and pclose() instead.

If the former, look at the return value from system() (and use the documentation for waitpid() to interpret it).

How do I execute a command and get the output of the command within C++ using POSIX?

#include <cstdio>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <array>

std::string exec(const char* cmd) {
std::array<char, 128> buffer;
std::string result;
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
if (!pipe) {
throw std::runtime_error("popen() failed!");
}
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
result += buffer.data();
}
return result;
}

Pre-C++11 version:

#include <iostream>
#include <stdexcept>
#include <stdio.h>
#include <string>

std::string exec(const char* cmd) {
char buffer[128];
std::string result = "";
FILE* pipe = popen(cmd, "r");
if (!pipe) throw std::runtime_error("popen() failed!");
try {
while (fgets(buffer, sizeof buffer, pipe) != NULL) {
result += buffer;
}
} catch (...) {
pclose(pipe);
throw;
}
pclose(pipe);
return result;
}

Replace popen and pclose with _popen and _pclose for Windows.

How to execute a command and get return code stdout and stderr of command in C++

From the man-page of popen:

The pclose() function waits for the associated process to terminate  and returns the exit status of the command as returned by wait4(2).

So, calling pclose() yourself (instead of using std::shared_ptr<>'s destructor-magic) will give you the return code of your process (or block if the process has not terminated).

std::string exec(const char* cmd) {
std::array<char, 128> buffer;
std::string result;

auto pipe = popen(cmd, "r"); // get rid of shared_ptr

if (!pipe) throw std::runtime_error("popen() failed!");

while (!feof(pipe)) {
if (fgets(buffer.data(), buffer.size(), pipe) != nullptr)
result += buffer.data();
}

auto rc = pclose(pipe);

if (rc == EXIT_SUCCESS) { // == 0

} else if (rc == EXIT_FAILURE) { // EXIT_FAILURE is not used by all programs, maybe needs some adaptation.

}
return result;
}

Getting stderr and stdout with popen(), I'm afraid you'd need to redirect the output of stderr to stdout from the command-line you're passing to popen() by adding 2>&1. This has the inconvinience that both streams are unpredictably mixed.

If you really want to have two distinguished file-descriptors for stderr and stdout, one way to do it is to do the forking yourself and to duplicate the new processes stdout/stderr to two pipes which are accessible from the parent process. (see dup2() and pipe()). I could go into more detail here, but this is quite a tedious way of doing things and much care must be taken. And the internet is full of examples.

viewing output of system() call in C++

Use popen instead of system. See example here https://msdn.microsoft.com/en-us/library/96ayss4b.aspx

char   psBuffer[128];
FILE *pPipe;

if( (pPipe = _popen( "set PATH=%PATH%;C:/Program Files (x86)/myFolder/bin", "rt" )) == NULL )
exit( 1 );

then

while(fgets(psBuffer, 128, pPipe)) {
printf(psBuffer);
}

if (feof( pPipe))
printf( "\nProcess returned %d\n", _pclose( pPipe ) );

An alternative way to get console output of system() function

As mentioned by @Charles Duffy, and @Kevin, system() is not the function you want. popen() is more suitable. The following should work. Please note, if you are using gcc and compile with -std=c99 flag, you need to add #define _POSIX_C_SOURCE 2 before #include <stdio.h>

#include <stdio.h>
#include <error.h>

#define PATH_MAX 1024

int main(void)
{
FILE *fp;
int status;
char path[PATH_MAX];

fp = popen("iptables -t filter -L", "r");
if (fp == NULL)
{
perror("popen");
return -1;
}

while (fgets(path, PATH_MAX, fp) != NULL)
{
printf("%s", path);
/* do something you want with the return data */
}

status = pclose(fp);
if (status == -1)
{
perror("pclose");
}
return 0;
}


Related Topics



Leave a reply



Submit