Reputation: 67
From what I can see there is a lot of info on piping and file redirection. But I can't find anything specific about doing both piping and file redirection. If there is something like that that I maybe missed please link it for me if you don't mind.
What I want to be able to do is execute a command in the shell like ls -l | grep total > test.txt
so that grep
grabs the total from ls -l
and feeds it into test.txt
.
The way I have my program setup, everything is broken up into so if() logic to determine what kind of symbols are used. Here is what I have working for only a pipe, and only a redirect. I'm just a little confused about how to proceed with when I get a |
and a >
. How can I combine the two?
else if(pipey && !redirect)
{
char main_str[1024];
char pipe_str[1024];
char *left_args[100] = {NULL};
char *right_args[100] = {NULL};
strcpy(main_str, string);
int fd[2];
char *token = strchr(main_str, '|');
*token = '\0';
token++;
while(*token == ' ')
{
token++;
}
strcpy(pipe_str, token);
int i = 0;
for(token = strtok(main_str, " \n"), i = 0; token; token = strtok(NULL, " \n" ), ++i)
{
left_args[i] = token;
}
i = 0;
for(token = strtok(pipe_str, " \n"), i = 0; token; token = strtok(NULL, " \n" ), ++i)
{
right_args[i] = token;
}
if(pipe(fd) == -1)
{
return 2;
}
c1_pid = fork();
if(c1_pid < 0)
{
return 3;
}
if(c1_pid == 0)
{
dup2(fd[1], STDOUT_FILENO);
close(fd[0]);
close(fd[1]);
execvp(left_args[0], left_args);
}
c2_pid = fork();
if(c2_pid < 0)
{
return 4;
}
if(c2_pid == 0)
{
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
close(fd[1]);
execvp(right_args[0], right_args);
}
close(fd[0]);
close(fd[1]);
waitpid(c1_pid, NULL, 0);
waitpid(c2_pid, NULL, 0);
}
// A single redirect given by user
else if(!pipey && redirect)
{
char main_str[1024];
char pipe_str[1024];
char *left_args[100] = {NULL};
char *middle_args[100] = {NULL};
char *right_args[100] = {NULL};
strcpy(main_str, string);
char *token = strchr(main_str, '>');
*token = '\0';
token++;
while(*token == ' ')
{
token++;
}
strcpy(pipe_str, token);
int i = 0;
for(token = strtok(main_str, " \n"), i = 0; token; token = strtok(NULL, " \n" ), ++i)
{
left_args[i] = token;
}
i = 0;
for(token = strtok(pipe_str, " \n"), i = 0; token; token = strtok(NULL, " \n" ), ++i)
{
right_args[i] = token;
}
c1_pid = fork();
if(c1_pid < 0)
{
return 5;
}
if(c1_pid == 0)
{
int file = open(right_args[0], O_WRONLY | O_CREAT, 0777);
if(file == -1)
{
return 6;
}
dup2(file, STDOUT_FILENO);
execvp(left_args[0], left_args);
close(file);
}
waitpid(c1_pid, NULL, 0);
}
Again, just wondering how I can take what I currently have, and apply it toward if both symbols occur. All the parsing stuff is fine, its just the piping and duping stuff I'm a little unsure about.
Upvotes: 1
Views: 667
Reputation: 362037
Separate the two concepts into a hierarchy:
command | command | command
.program arg1 arg2 arg3 >redirect1 2>redirect2 <redirect3
.Handle pipelines in one function and commands/redirects in a second, subordinate function.
This will let you break up this monolithic code block into smaller pieces. Pipelines and redirects are orthogonal concepts. They belong in separate, independent functions so they don't have to know about each other.
You should also decouple parsing from execution. Smart decoupling is crucial to keeping code complexity at a manageable level.
Don't parse the command-line and execute child processes in the same block of code. Split them apart. Perform string parsing, pull out the relevant pieces, and then call separate function(s) to actually fork/open/dup2/exec/waitpid.
Upvotes: 1