Code to redirect input AND output in a shell
<p>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.</p>

<p>e.g. </p>

<pre><code> " echo hi kenny &gt; kenny.txt "  works

 " cat in.txt | less "      works
</code></pre>

<p>However,(assume in.txt is a random alphabet file)</p>

<pre><code> " sort -u &lt; in.txt &gt; out.txt " does not work for  both, only for the input(&lt;).
</code></pre>

<p>My code is roughly as follows:</p>

<pre><code>int main(int argc, char* argv[]){

 readLine();

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

}
</code></pre>

<p>Let's assume thats all needed. No pipes etc.</p>

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

<p>lineHasSpecialSymbols() detects the first instance of '&lt;' or '>'and returns.</p>

<p>Here's the tricky part in how inRedirection() works:</p>

<pre><code>void inRedirection(void) {
extractCommand("&lt;");
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");
 }
}
</code></pre>

<p>outRedirection():</p>

<pre><code>void outRedirection(void) {
extractCommand("&gt;");
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");
 }
}
</code></pre>

<p>Finally, extractCommand():</p>

<pre><code>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++;
     }
  }
}
</code></pre>

<p>Sorry, for the huge code. Here's the problem:</p>

<p>Let's say that I type the command : </p>

<p>" sort -u &lt; in.txt > out.txt "</p>

<p>The code will detect the '&lt;' and extract the command into two parts. </p>

<pre><code>args[0] = "sort"   args2[0] = "in.txt"    args2[2] = "out.txt"
args[1] = "-u"     args2[1] = "&gt;"
</code></pre>

<p>It will only the "sort -u &lt; 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"?</p>

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