2

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.

3
  • 1
    don't fork in your "outRedirection" function. (Actually, don't have an "outRedirection" function!). Fork. Then parse the command line. If you see a '>' symbol, dup stdout to the file named. Keep parsing. If you see a '<' symbol, dup stdin. Commented Apr 28, 2016 at 13:43
  • 1
    You might want to learn first how to properly write a parser in general and an interpreter specifically. There is a lot of information to be found by a simple serach, e.g. "compiler construction" (a lot of related stuff). Commented Apr 28, 2016 at 13:52
  • And on top of what Olaf said, read the man dup2. But properly parsing a script should come first (e.g. check the GNU bison). Commented Apr 28, 2016 at 15:25

1 Answer 1

1

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");
 }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.