Skip to content

Instantly share code, notes, and snippets.

@skanga
Last active April 1, 2018 02:06
Show Gist options
  • Save skanga/0ebd103c619a0ec79a0cb4fa2ddef977 to your computer and use it in GitHub Desktop.
Save skanga/0ebd103c619a0ec79a0cb4fa2ddef977 to your computer and use it in GitHub Desktop.
Here's an example of how to pipe an arbitrary number of commands together using C including input and output redirection. The demo example in main() executes the command "grep nologin < /etc/passwd | awk "{print $1}" | sort > zzz". In case you do not need the file redirection then either one or both can be set to NULL.
/**
* gcc -o runpipe runpipe.c && ./runpipe
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
struct command
{
const char **argv;
};
int spawn_proc (int in, int out, struct command *cmd)
{
pid_t pid;
if ((pid = fork ()) == 0)
{
if (in != 0)
{
dup2 (in, 0);
close (in);
}
if (out != 1)
{
dup2 (out, 1);
close (out);
}
return execvp (cmd -> argv [0], (char * const *) cmd -> argv);
}
return pid;
}
int fork_pipes (int n, struct command *cmd)
{
int i;
pid_t pid;
int in, fd [2];
/* The first process should get its input from the original file descriptor 0 */
in = 0;
/* Note the loop bound, we spawn here all, but the last stage of the pipeline */
for (i = 0; i < n - 1; ++i)
{
pipe (fd);
/* fd [1] is the write end of the pipe so connect it to 'in' from the prev iteration */
spawn_proc (in, fd [1], cmd + i);
/* No need for the write end of the pipe, the child will write here */
close (fd [1]);
/* Keep the read end of the pipe, the next child will read from there */
in = fd [0];
}
/* Last stage of pipeline - set stdin be the read end of the previous pipe
and output to the original file descriptor 1 */
if (in != 0)
dup2 (in, 0);
/* Execute the last stage with the current process. */
return execvp (cmd [i].argv [0], (char * const *) cmd [i].argv);
}
int runPipe (char *inFile, char *outFile, int cmdCount, struct command *cmd)
{
int in, out;
if (inFile && inFile[0])
{
in = open (inFile, O_RDONLY); // open input file
dup2 (in, 0); // replace standard input with input file
close (in); // close unused file descriptor
}
if (outFile && outFile[0])
{
out = open (outFile, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IRGRP | S_IWGRP | S_IWUSR); // open output file
dup2 (out, 1); // replace standard output with output file
close (out); // close unused file descriptors
}
return fork_pipes (cmdCount, cmd); // execute
}
// Executes the command "grep nologin < /etc/passwd | awk "{print $1}" | sort > zzz".
int main (int argc, char **argv)
{
//char *inFile = NULL;
char *inFile = "/etc/passwd";
char *outFile = NULL;
//char *outFile = "zzz";
const char *grep[] = {"grep", "nologin", NULL};
const char *awk[] = {"awk", "-F:", "{print $1}", NULL};
const char *sort[] = {"sort", NULL};
struct command cmd [] = { {grep}, {awk}, {sort} };
runPipe (inFile, outFile, 3, cmd);
}
int main2 ()
{
const char *ifconfig[] = { "ifconfig", "tun0", 0 };
const char *awk[] = { "awk", "/destination/ {print $2}", 0 };
struct command cmd [] = { {ifconfig}, {awk} };
return fork_pipes (2, cmd);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment