22

I just want to know which is the best way to execute an external command in C++ and how can I grab the output if there is any?

Edit: I Guess I had to tell that I'm a newbie here in this world, so I think I'm gonna need a working example. For example I want to execute a command like:

ls -la

how do I do that?

0

3 Answers 3

24

Use the popen function.

Example (not complete, production quality code, no error handling):

FILE* file = popen("ls", "r");
// use fscanf to read:
char buffer[100];
fscanf(file, "%100s", buffer);
pclose(file);
Sign up to request clarification or add additional context in comments.

9 Comments

@Daniel This is not production code. This is an answer on an online forum that is supposed to give one the high-level idea of the popen function and its arguments. Anyone in the habit of treating all Stack Overflow answers as production code has more serious problems than this. Also, any buffer that has the possibility overflow is not a DEAD SERIOUS SECURITY THREAT WORTHY OF SHOUTING AT. Without a specific threat model and knowing what is trusted and what is not in the particular environment something is applied to, discussion about security is moot.
@Daniel I hear you. Sure, a more complete answer warning about all possible gotchas could be a better answer. You might be able to write a book about gotchas in three lines of code. It is, however, clear that what's germane to this question is "popen" and not how you'd further process the output of the external process...
...I felt this answer, as is, is helpful enough for people who can figure the rest out. That's why I wrote it. Yes, it is not perfect. That's why Stack Overflow has all these nice features so that you can comment on things to be careful about, or, better yet, edit or contribute your own, better answer, instead of launching ad-hominem attacks against other volunteer contributors. This is especially disappointing considering I did post a warning that clearly implies recommending against direct use in production code.
@MehrdadAfshari You're too kind to have updated your answer; I hope people noticed.
@Daniel I think it was pretty clear back then (and today as well) that in general executing external command as they are is not really a good practice in production for many reasons and among others is the fact that you can simply change that command to something else.. so it's pretty much common sense.. and no need to even mentioning anything extra (the list could be huge) since it answers exactly what is being asked! I would even revert the answer to the original :)
|
20

An example:

#include <stdio.h>

int main() {
    FILE * f = popen( "ls -al", "r" );
    if ( f == 0 ) {
        fprintf( stderr, "Could not execute\n" );
        return 1;
    }
    const int BUFSIZE = 1000;
    char buf[ BUFSIZE ];
    while( fgets( buf, BUFSIZE,  f ) ) {
        fprintf( stdout, "%s", buf  );
    }
    pclose( f );
}

9 Comments

forgot return 0 at the end of main. and use sizeof( buff ) instead 1000 in fgets :)
C++ does not require a return at end of main.
True, but it's nice to have the return, so that it's obvious what's going to come out of the program.
wget writes its status messages to stderr - run it with the --quiet option
@Dave Jarvis Please do not feel free to "improve" my answers by adding unnecessary code.
|
17

popen definitely does the job that you're looking for, but it has a few drawbacks:

  • It invokes a shell on the command you're executing (which means that you need to untaint any user provided command strings)
  • It only works in one direction, either you can provide input to the subprocess or you can read its output.

If you want invoke a subprocess and provide input and capture output then you'll have to do something like this:

int Input[2], Output[2];

pipe( Input );
pipe( Output );

if( fork() )
{
    // We're in the parent here.
    // Close the reading end of the input pipe.
    close( Input[ 0 ] );
    // Close the writing end of the output pipe
    close( Output[ 1 ] );

    // Here we can interact with the subprocess.  Write to the subprocesses stdin via Input[ 1 ], and read from the subprocesses stdout via Output[ 0 ].
    ...
}
else
{    // We're in the child here.
     close( Input[ 1 ] );
     dup2( Input[ 0 ], STDIN_FILENO );
     close( Output[ 0 ] );
     dup2( Output[ 1 ], STDOUT_FILENO );

     execlp( "ls", "-la", NULL );
}

Of course, you can replace the execlp with any of the other exec functions as appropriate.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.