Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I am looking for a way to get the output of a command when it is run from within a C++ program. I have looked at using the system() function, but that will just execute a command. Here's an example of what I'm looking for:

std::string result = system( "./some_command" ) ;

I need to run an arbitrary command and get it's output. I've looked at Boost.org but I have not found anything that will give me what I need.

share|improve this question

5 Answers

up vote 90 down vote accepted
#include <string>
#include <iostream>
#include <stdio.h>

std::string exec(char* cmd) {
    FILE* pipe = popen(cmd, "r");
    if (!pipe) return "ERROR";
    char buffer[128];
    std::string result = "";
    while(!feof(pipe)) {
    	if(fgets(buffer, 128, pipe) != NULL)
    		result += buffer;
    }
    pclose(pipe);
    return result;
}

Replace popen and pclose with _popen and _pclose for Windows.

share|improve this answer
6  
Be aware that this will only grab stdout and not stderr. – kalaxy Oct 31 '11 at 23:53
2  
You can redirect stderr to stdout by appending "2>&1" to the command. Docs: microsoft.com/resources/documentation/windows/xp/all/proddocs/… – waqas Dec 17 '11 at 4:22
1  
Also be aware that an exception can occur in result += buffer, so the pipe might not be properly closed. – larsmans May 19 '12 at 20:27
@larsmans What kind of exceptions? – Janis Mar 14 at 16:05
1  
@Janis: bad_alloc. – larsmans Mar 14 at 22:00
show 1 more comment

I'd use popen() (++waqas).

But sometimes you need reading and writing...

Seems like nobody does things the hard way any more.

(Assuming a Unix/Linux/Mac environment, or perhaps Windows with a POSIX compatibility layer...)

enum PIPE_FILE_DESCRIPTERS
{
  READ_FD  = 0,
  WRITE_FD = 1
};

enum CONSTANTS
{
  BUFFER_SIZE = 100
};

int
main()
{
  int       parentToChild[2];
  int       childToParent[2];
  pid_t     pid;
  string    dataReadFromChild;
  char      buffer[ BUFFER_SIZE + 1 ];
  ssize_t   readResult;
  int       status;

  ASSERT_IS(0, pipe(parentToChild));
  ASSERT_IS(0, pipe(childToParent));

  switch ( pid = fork() )
  {
    case -1:
      FAIL( "Fork failed" );
      exit(-1);

    case 0: /* Child */
      ASSERT_NOT(-1, dup2( parentToChild[ READ_FD  ], STDIN_FILENO  ) );
      ASSERT_NOT(-1, dup2( childToParent[ WRITE_FD ], STDOUT_FILENO ) );
      ASSERT_NOT(-1, dup2( childToParent[ WRITE_FD ], STDERR_FILENO ) );
      ASSERT_IS(  0, close( parentToChild [ WRITE_FD ] ) );
      ASSERT_IS(  0, close( childToParent [ READ_FD  ] ) );

          /*   file,  arg0,  arg1,   arg2 */
      execlp(  "ls",  "ls",  "-al",  "--color" );

      FAIL( "This line should never be reached!!!" );
      exit(-1);


    default: /* Parent */
      cout << "Child " << pid << " process running..." << endl;

      ASSERT_IS(  0, close( parentToChild [ READ_FD  ] ) );
      ASSERT_IS(  0, close( childToParent [ WRITE_FD ] ) );

      while ( true )
      {
        switch ( readResult = read( childToParent[ READ_FD ],
                                    buffer, BUFFER_SIZE ) )
        {
          case 0: /* End-of-File, or non-blocking read. */
            cout << "End of file reached..."         << endl
                 << "Data received was ("
                 << dataReadFromChild.size() << "):" << endl
                 << dataReadFromChild                << endl;

            ASSERT_IS( pid, waitpid( pid, & status, 0 ) );

            cout << endl
                 << "Child exit staus is:  " << WEXITSTATUS(status) << endl
                 << endl;

            exit(0);


          case -1:
            if ( (errno == EINTR) || (errno == EAGAIN) )
            {
              errno = 0;
              break;
            }
            else
            {
              FAIL( "read() failed" );
              exit(-1);
            }

          default:
            dataReadFromChild . append( buffer, readResult );
            break;
        }
      } /* while ( true ) */
  } /* switch ( pid = fork() )*/
}

You also might want to play around with select() and non-blocking reads.

fd_set          readfds;
struct timeval  timeout;

timeout.tv_sec  = 0;    /* seconds */
timeout.tv_usec = 1000; /* microseconds */

FD_ZERO(&readfds);
FD_SET( childToParent[ READ_FD ], &readfds );

switch ( select ( 1 + childToParent[READ_FD], &readfds, (fd_set*)NULL, (fd_set*)NULL, & timeout ) )
{
  case 0: /* Timeout expired */
    break;

  case -1:
    if ( (errno == EINTR) || (errno == EAGAIN) )
    {
      errno = 0;
      break;
    }
    else
    {
      FAIL( "Select() Failed" );
      exit(-1);
    }

  case 1:  /* We have input */
    readResult = read( childToParent[ READ_FD ], buffer, BUFFER_SIZE );
    // However you want to handle it...
    break;

  default:
    FAIL( "How did we see input on more than one file descriptor?" );
    exit(-1);
}
share|improve this answer
The hard way is right :) I like the idea with select() call, though in this case, I actually need to wait until the task completes. I'll keep this code for another project I have :) – Misha M Jan 27 '09 at 2:21
...or you could use the existing posix_spawnp function – Per Johansson Jan 3 at 15:18

You can use the library Boost.Process. It's not officially part of boost though. I've have seen it working nicely for others. Unfortunately, boost.process progress apparently has been stalled. pstreams is another (apparently active) project. Certainly worth a try i would say - but it's only for posix compatible operation systems.

share|improve this answer

Getting both stdout and stderr (and also writing to stdin, not shown here) is easy peasy with my pstreams header, which defines iostream classes that work like popen:

#include <pstream.h>
#include <string>
#include <iostream>

int main()
{
  // run a process and create a streambuf that reads its stdout and stderr
  redi::ipstream proc("./some_command", redi::pstreams::pstderr);
  std::string line;
  // read child's stdout
  while (std::getline(proc.out(), line))
    std::cout << "stdout: " << line << 'n';
  // read child's stderr
  while (std::getline(proc.err(), line))
    std::cout << "stderr: " << line << 'n';
} 
share|improve this answer
popen is the correct solution to use when either input or output communication is desired from the child process, but not both. – DragonLord Jun 23 '12 at 20:44
1  
I disagree. popen requires you to use the C stdio API, I prefer the iostreams API. popen requires you to manually clean up the FILE handle, pstreams do that automatically. popen only accepts a const char* for the argument, which requires care to avoid shell injection attacks, pstreams allows you to pass a vector of strings similar to execv, which is safer. popen gives you nothing but a pipe, pstreams tells you the child's PID allowing you to send signals e.g. to kill it if it's blocked or not exiting. All of those are advantages even if you only want unidirectional IO. – Jonathan Wakely Oct 10 '12 at 17:08

Two possible approaches.

1/ I don't think popen() is part of the C++ standard (it's part of POSIX from memory) but it's available on every UNIX I've worked with (and you seem to be targeting UNIX since your command is "./some_command").

2/ On the off-chance that there is no popen(), you can use system( "./some_command >/tmp/some_command.out" ) ; then use the normal I/O functions to process the output file.

share|improve this answer
Thanks for popen, I'm going to use that for now and I'll worry about non-POSIX systems if that comes up. – Misha M Jan 27 '09 at 2:25

protected by Community Mar 14 at 15:59

This question is protected to prevent "thanks!", "me too!", or spam answers by new users. To answer it, you must have earned at least 10 reputation on this site.

Not the answer you're looking for? Browse other questions tagged or ask your own question.