I am writing a small linux shell in C and am so very close to being done. I take in a command from the user and store it in args, delimited by spaces. In the following example, let's say that args contains the following:
args[] = {"ls", "-l", "|", "wc"};
My function takes in args and also takes in how many pipes there are. I've commented my code as much as possible. Here it is:
int do_command(char **args, int pipes) {
// The number of commands to run
const int commands = pipes + 1;
int i = 0;
int pipefds[2*pipes];
for(i = 0; i < pipes; i++){
if(pipe(pipefds + i*2) < 0) {
perror("Couldn't Pipe");
exit(EXIT_FAILURE);
}
}
int pid;
int status;
int j = 0;
int k = 0;
int s = 1;
int place;
int commandStarts[10];
commandStarts[0] = 0;
// This loop sets all of the pipes to NULL
// And creates an array of where the next
// Command starts
while (args[k] != NULL){
if(!strcmp(args[k], "|")){
args[k] = NULL;
// printf("args[%d] is now NULL", k);
commandStarts[s] = k+1;
s++;
}
k++;
}
for (i = 0; i < commands; ++i) {
// place is where in args the program should
// start running when it gets to the execution
// command
place = commandStarts[i];
pid = fork();
if(pid == 0) {
//if not last command
if(i < pipes){
if(dup2(pipefds[j + 1], 1) < 0){
perror("dup2");
exit(EXIT_FAILURE);
}
}
//if not first command&& j!= 2*pipes
if(j != 0 ){
if(dup2(pipefds[j-2], 0) < 0){
perror("dup2");
exit(EXIT_FAILURE);
}
}
int q;
for(q = 0; q < 2*pipes; q++){
close(pipefds[q]);
}
// The commands are executed here,
// but it must be doing it a bit wrong
if( execvp(args[place], args) < 0 ){
perror(*args);
exit(EXIT_FAILURE);
}
}
else if(pid < 0){
perror("error");
exit(EXIT_FAILURE);
}
j+=2;
}
for(i = 0; i < 2 * pipes; i++){
close(pipefds[i]);
}
for(i = 0; i < pipes + 1; i++){
wait(&status);
}
}
My problem is that while the program is kind of executing correctly, it is behaving strangely and I was hoping you could help me out.
For example hen I run ls | wc, the output is that of ls | wc, but then it also prints the output of a simple ls right below it, even though it should just be the wc of the output.
As another example, when I try ls -l | wc, the first number of wc shows up, but then the output of ls -l shows up below it, even though it should just be the wc of the output.
Thanks in advance! :)
The C shell is an interactive command interpreter and a command programming language. It uses syntax that is similar to the C programming language. The csh command starts the C shell.
A pipe is a form of redirection (transfer of standard output to some other destination) that is used in Linux and other Unix-like operating systems to send the output of one command/program/process to another command/program/process for further processing.
Okay, I have found one little error. This
if( execvp(args[place], args) < 0 ){
should be
if( execvp(args[place], args+place) < 0 ){
Your version used the args for the first command for all the others. Other than that, it works for me.
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