[LC++]Executing Shell Commands

Paul Gearon pag at PISoftware.com
Fri May 30 15:03:01 UTC 2003


On Fri, 30 May 2003, James Mclean wrote:

> I am beginning to learn C++ after playing with C for a while, and I am
> executing some shell commands with the function execl().
> I am basically wondering what other functions are available for shell
> command calls, because execl() returns an int, and prints the results of
> the command to the stdout.
> What I need is to put the results of the command into and array or
> string, rather than print to stdout.
>
> I have read the execl(3) manpage, but I cannot see any hints in this
> page.
>
> What would this function be?

If you just need the output of the process then try using popen.

A trivial program which reads from the process "/bin/cat /etc/hosts" and
prints it to stdout could be...

#include <stdio.h>
#define BUFFERSIZE 256

int main() {
  FILE* p = popen("/bin/cat /etc/hosts", "r");
  while (!feof(p)) {
    int n;
    char buffer[BUFFERSIZE];
    if (0 < (n = fread(buffer, 1, BUFFERSIZE, p)))
      fwrite(buffer, 1, n, stdout);
  }
  pclose(p);
  return 0;
}


NOTE: The above code is horrible... it just provides an example.  Do error
checking, etc, as appropriate.

A better answer to your question is a little more complex.

execl replaces the current process with another process.  Anything which
this new process sends to stdout will go to the stdout of the original
process which called execl.

Firstly, if you need to "capture" the output of another program, you'll
need to fork() before calling execl() in the child process.  This is so
that the original program doesn't disappear.

Secondly, before calling execl() in the child process you need to attach
stdout (and probably stdin) to something that the parent can talk to.
Usually, you'll use pipes for this, and you copy them over the child's
stdin and stdout (and usually stderr) with dup2().  Then when the child
calls execl anything that would normally go to stdout will go to the pipe
you set up for it.  (you can also use sockets, fifos, and basically any
file descriptor type that makes sense).

The following is a simple version of this sort of code.  It just reads
from the child process, and doesn't write to it (though it could).  Note,
this just proves the concept, it's not tidy code...

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

#define BUFFERSIZE 256

int main() {
  // create the pipes
  int fds_poci[2], fds_pico[2];
  if (0 != pipe(fds_poci) || 0 != pipe(fds_pico)) return 1;

  // create the child
  if (0 == fork()) {
    // in the child process
    dup2(fds_poci[0], 0);  // copy reading end to stdin
    dup2(fds_pico[1], 1);  // copy writing end to stdout
    // close the pipes as they're now redundant
    close(fds_poci[0]);
    close(fds_poci[1]);
    close(fds_pico[0]);
    close(fds_pico[1]);
    execl("/bin/cat", "cat", "/etc/hosts", NULL);
    return 2;  // hopefully never gets here
  }

  // in the parent process
  close(fds_poci[0]);  // close reading end
  close(fds_pico[1]);  // close writing end

  // read from child and write to stdout
  int n;
  char buffer[BUFFERSIZE];
  while (0 < (n = read(fds_pico[0], buffer, BUFFERSIZE))) {
    write(1, buffer, n);
  }

  close(fds_poci[1]);
  close(fds_pico[0]);

  return 0;
}




Regards,
Paul Gearon

Software Engineer                Telephone:   +61 7 3876 2188
Plugged In Software              Fax:         +61 7 3876 4899
http://www.PIsoftware.com        PGP Key available via finger

Catapultam habeo. Nisi pecuniam omnem mihi dabis, ad caput tuum saxum
immane mittam.
(Translation from latin: "I have a catapult. Give me all the money,
or I will fling an enormous rock at your head.")






More information about the tuxCPProgramming mailing list