Joseph Athan
Joseph Athan

Reputation: 105

Code to redirect input AND output in a shell

I have created a shell program that can more or less do what the normal linux shell does. My program can redirect input OR output correctly,but not both at the same time. Any solutions online so far, haven't been useful to me.

e.g.

 " echo hi kenny > kenny.txt "  works

 " cat in.txt | less "      works

However,(assume in.txt is a random alphabet file)

 " sort -u < in.txt > out.txt " does not work for  both, only for the input(<).

My code is roughly as follows:

int main(int argc, char* argv[]){

 readLine();

 if (lineHasSpecialSymbols()) {
    if(hasInput()){
       inRedirection();
    }else
      outRedirection();
 }

}

Let's assume thats all needed. No pipes etc.

readLine() reads a line from the terminal and saves them in args[]

lineHasSpecialSymbols() detects the first instance of '<' or '>'and returns.

Here's the tricky part in how inRedirection() works:

void inRedirection(void) {
extractCommand("<");
int fd;
if ((pid = fork()) == -1) {
  perror("fork");
  exit(1);
}
if (pid == 0) {
  close(0);
  //open the file args2[0] and use it as standard input
  fd = open(args2[0], O_RDWR);
  execvp(args[0], args);
  perror("execv");
  exit(1);
}
if (pid != 0) {
  wait(NULL);
  printf("Done ");
  printf(args[0]);
  printf(".\n");
 }
}

outRedirection():

void outRedirection(void) {
extractCommand(">");
int fd;
if ((pid = fork()) == -1) {
  perror("fork");
  exit(1);
}
if (pid == 0) {
  close(1);
  fd = creat(args2[0], 0644);
  execvp(args[0], args);
  perror("execv");
  exit(1);
}
if (pid != 0) {
  wait(NULL);
  printf("Done ");
  printf(args[0]);
  printf(".\n");
 }
}

Finally, extractCommand():

void extractCommand(char* symbol) {
int i;
int count = 0;
for (i = 0; args[i] != NULL; i++)
  if (!strcmp(args[i], symbol)) {
     args[i] = NULL;
     while (args[i+1] != NULL) {
           args2[count] = args[i+1];
           args[i+1] = NULL;
           i++;
           count++;
     }
  }
}

Sorry, for the huge code. Here's the problem:

Let's say that I type the command :

" sort -u < in.txt > out.txt "

The code will detect the '<' and extract the command into two parts.

args[0] = "sort"   args2[0] = "in.txt"    args2[2] = "out.txt"
args[1] = "-u"     args2[1] = ">"

It will only the "sort -u < in.txt" and not the rest. My question is how can I change my code to work as an intented? Also, how can I do that for more than two commands? For example : "ls -l /home/user | sort -u | wc -l > in.txt"?

I've thought of some algorithms like making a third args (args3), but that would collide in the case of more that two commands.

Upvotes: 2

Views: 1708

Answers (1)

Marios Ath
Marios Ath

Reputation: 638

I suggest you change your methods.

int outRedirection(void) {
  int i;
  int j;
  for(i = 0; args[i] != NULL; i++) {
    // Look for the >
    if(args[i][0] == '>') {
      args[i] = NULL;
      // Get the filename
      if(args[i+1] != NULL) {
    output_filename[0] = args[i+1];
      } else {
    return -1;
      }
            //For- loop to make input AND output functional
           for(j = i; args[j-1] != NULL; j++) {
                        args[j] = args[j+2];
           }
      return 1;
    }
  }
  return 0;
}

Do the same thing for input and then execute like so:

    void IOcommand(void){
    if ((pid = fork())== -1){
        perror("fork");
        exit(1);
    }if (pid == 0){

    if (input == 1)
        freopen(input_filename[0], "r", stdin);

    if (output == 1)
        freopen(output_filename[0], "w+", stdout);

        execvp(args[0],args);
        exit(-1);
 }
 if (pid != 0 ){
     wait(NULL);
     printf("Done ");
     printf(args[0]);
     printf(".\n");
 }
}

Upvotes: 1

Related Questions