How to Execute a Command and Get the Output of the Command Within C++ Using Posix

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(), 128, 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.

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 information from the waitpid() information to interpret it).

How can I execute terminal commands from a C program?

how to execute terminal commands from my C program
...
(I would like to get the output)

Look at popen

Example

#include <stdio.h>

int main(int argc, char ** argv)
{
if (argc != 2) {
fprintf(stderr, "Usage: %s <command>\n", *argv);
return -1;
}

FILE * fp = popen(argv[1], "r");

if (fp != 0) {
char s[64];

while (fgets(s, sizeof(s), fp) != NULL)
fputs(s, stdout);

pclose(fp);
}

return 0;
}

Compilation and executions:

bruno@bruno-XPS-8300:/tmp$ gcc -Wall o.c
bruno@bruno-XPS-8300:/tmp$ ./a.out date
samedi 11 avril 2020, 17:58:45 (UTC+0200)
bruno@bruno-XPS-8300:/tmp$ a.out "date | wc"
1 6 42
bruno@bruno-XPS-8300:/tmp$ ./a.out "cat o.c"
#include <stdio.h>

int main(int argc, char ** argv)
{
if (argc != 2) {
fprintf(stderr, "Usage: %s <command>\n", *argv);
return -1;
}

FILE * fp = popen(argv[1], "r");

if (fp != 0) {
char s[64];

while (fgets(s, sizeof(s), fp) != NULL)
fputs(s, stdout);

pclose(fp);
}

return 0;
}
bruno@bruno-XPS-8300:/tmp$

How to store command output and exitcode from terminal in a variable

Assuming the code provided in the article is correct and does what it should do, it is already doing all you need. The exit code and output are returned from the exec function.

You only have to use the returned CommandResult and access its members:

int main() {
auto result = Command::exec("echo blablub");
std::cout << result.output << "\n":
std::cout << result.exitstatus << "\n";
}

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.



Related Topics



Leave a reply



Submit