Last active
April 1, 2018 02:06
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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