I have been working on a custom shell script and have come to a small error when redirecting output with the code given below. In its current state the code works perfectly but when passing to execvp args throws errors such as : (ls ">" no such file or directory). I know this is because it is passing the whole args[] to the parent shell which isn't working. Adding in the args[j] = NULL takes away the "<"/ ">" thus fixing the error, but also causes the redirections to not work anymore. How can I get it to not throw an error but also work properly? I have read multiple versions of this question but cant seem to find an answer. Thanks in advance for any help.
switch (fork()){
case -1:
fprintf(stderr, "error forking");
case 0://CHILD
for(int j = 0; j < size; j++){
if(!strcmp(args[j], "<")){//looking for input character
++ext;
if((in = open(args[j+1], O_RDONLY)) < 0){//open file for reading
fprintf(stderr, "error opening file\n");
}
dup2(in, STDIN_FILENO);//duplicate stdin to input file
close(in);//close after use
//args[j] = NULL;
}//end input chech
if(!strcmp(args[j],">")){//looking for output character
++ext;
out = creat(args[j+1], 0644);//create new output file
dup2(out, STDOUT_FILENO);//redirect stdout to file
close(out);//close after usere
// args[j] = NULL;
}//end output check
if(!strcmp(args[j], ">>")){//looking for append
++ext;
int append = open(args[j+1],O_CREAT | O_RDWR | O_APPEND, 0644);
dup2(append, STDOUT_FILENO);
close(append);
// args[j] = NULL;
}
}//end loop
execvp(args[0],args);//execute in parent
fprintf(stderr, "error in child execi \n");//error
exit(0);
default://PARENT
wait(&status); //wait for child to finish
}//end switch
Before the C shell executes a command, it scans the command line for redirection characters. These special notations direct the shell to redirect input and output. Opens the specified File (which is first variable, command, and file name expanded) as the standard input.
Regular output append >> operator This allows you to redirect the output from multiple commands to a single file. For example, I could redirect the output of date by using the > operator and then redirect hostname and uname -r to the specifications. txt file by using >> operator.
File redirection is generally known as I/O redirection on UNIX based systems, which allows the user to redefine where standard input comes from, or standard output goes. < operator is used to change where the standard input comes from.
When you are parsing redirections (e.g. <
, >
, >>
) and doing your open/dup2
, you have to strip them from the argument list you pass to execvp
.
So, given your args
, you need a second (e.g. args_clean
) argument list that you only copy over the program name and its arguments.
And, you need an extra increment of j
to skip over the redirection file in args
(i.e. just doing j + 1
isn't equivalent).
Here's the cleaned up child code [please pardon the gratuitous style cleanup]:
char *args_clean[size];
int cleanidx = 0;
for (int j = 0; j < size; j++) {
if (!strcmp(args[j], "<")) { // looking for input character
++j;
if ((in = open(args[j], O_RDONLY)) < 0) { // open file for reading
fprintf(stderr, "error opening file\n");
}
dup2(in, STDIN_FILENO); // duplicate stdin to input file
close(in); // close after use
continue;
} // end input chech
if (!strcmp(args[j], ">")) { // looking for output character
++j;
out = creat(args[j], 0644); // create new output file
dup2(out, STDOUT_FILENO); // redirect stdout to file
close(out); // close after usere
continue;
} // end output check
if (!strcmp(args[j], ">>")) { // looking for append
++j;
int append = open(args[j], O_CREAT | O_RDWR | O_APPEND, 0644);
dup2(append, STDOUT_FILENO);
close(append);
continue;
}
args_clean[cleanidx++] = args[j];
} // end loop
args_clean[cleanidx] = NULL;
execvp(args_clean[0], args_clean); // execute in parent
fprintf(stderr, "error in child execi \n"); // error
exit(0);
Also, see my answer here for something similar with pipes: fd leak, custom Shell
And, for a full blown shell, see my answer: Implementing input/output redirection in a Linux shell using C and look at the embedded pastebin link
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With