The reply here is what I use in my code, and it works fine, but I think it needs a little improvement: we need to move the read AFTER the wait, else there could be a race between the child and the original processes and the read result may be unpredictable, i.e. you could read a previous reply, or just a part of the expected current reply.
I post the same code as here, just adjusting the wait() position and adding some comments:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #define die(e) do { fprintf(stderr, "%s\n", e); exit(EXIT_FAILURE); } while (0); int main() { int link[2]; pid_t pid; char foo[4096]; if (pipe(link)==-1) die("pipe"); if ((pid = fork()) == -1) die("fork"); if(pid == 0) { dup2 (link[1], STDOUT_FILENO); close(link[0]); close(link[1]); execl("/bin/ls", "ls", "-1", (char *)0); die("execl"); } else { close(link[1]); wait(NULL); // N.B.: wait until the child process completes, else we could read a partial or empty output const int nbytes = read(link[0], foo, sizeof(foo)); // read the output once the child has completed printf("Output: (%.*s)\n", nbytes, foo); } return 0; }