<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
		>
<channel>
	<title>Comments on: C++ shell with forks and pipes</title>
	<atom:link href="http://www.3till7.net/2008/11/29/c-shell-with-forks-and-pipes/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.3till7.net/2008/11/29/c-shell-with-forks-and-pipes/</link>
	<description>Programming, espresso, and grumbling.</description>
	<lastBuildDate>Mon, 06 Feb 2012 13:27:31 +0000</lastBuildDate>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
	<item>
		<title>By: Ammar</title>
		<link>http://www.3till7.net/2008/11/29/c-shell-with-forks-and-pipes/comment-page-1/#comment-414775</link>
		<dc:creator>Ammar</dc:creator>
		<pubDate>Wed, 16 Mar 2011 22:30:22 +0000</pubDate>
		<guid isPermaLink="false">http://www.3till7.net/?p=1746#comment-414775</guid>
		<description>sorry should have stated its three files, it works, and trust me, its much easier to read if you put it in and IDE</description>
		<content:encoded><![CDATA[<p>sorry should have stated its three files, it works, and trust me, its much easier to read if you put it in and IDE</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Ammar</title>
		<link>http://www.3till7.net/2008/11/29/c-shell-with-forks-and-pipes/comment-page-1/#comment-414773</link>
		<dc:creator>Ammar</dc:creator>
		<pubDate>Wed, 16 Mar 2011 22:27:53 +0000</pubDate>
		<guid isPermaLink="false">http://www.3till7.net/?p=1746#comment-414773</guid>
		<description>Again thanks tons to sarah for posting her code which came a long way in helping me in my shell project.

heres my version of the shell which handles multiple piping, in_redirects, and out_redirects

thanks again sarah!

main:

//import header file
#include &quot;system_call.h&quot;

using namespace std;


int main() {

    //initialize three char array: one for original commands, and the next
    //two if if a pipe function is used with first containing the commands
    //in the correct order and the next contianing exactly which pipe type(&#124;, )
    char *cmds[MAX_ARGS], *ordered_cmds[MAX_ARGS], *cmd_types[MAX_ARGS];;

    //initialize enum pipe_redirect defined in the header file
    PipeRedirect pipe_redirect;
   
    //while &quot;C++_Shell&quot; prompt
    while (true) {
     
      cout &lt; &quot;;
      //immediately call parse_command function and return whther any pipes will be needed
      pipe_redirect = parse_command(cmds);
      //if pipes needed, call cmds_prep funtion to prepare two arrays for run_pipelines function
      if (pipe_redirect == PIPE_REDIRECT)          
      cmds_prep(cmds, ordered_cmds, cmd_types);
      //else execute commands with no pipes
      else
      exec_cmd(cmds);            

      //clear all respective arrays
      for (int i=0; i&lt;MAX_ARGS; i++)
      {
        ordered_cmds[i] = NULL;
        cmds[i] = NULL;
        cmd_types[i] = NULL;
      }

    } 

    
    //let OS know evrything is 
    return 0;
}

header file:

//include all librarys needed for system calls, string functions, and stream
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

//initialize enum piperedirect which can be either PIPE_REDIRECT indicating piping will be used
//or NEITHER
enum PipeRedirect {PIPE_REDIRECT, NEITHER};

//initialize constant integer at 256 to be used for most array limits and in most loops
const int MAX_ARGS = 256;

//initialize amp_flag and set to false
static bool amp_flag = false;


//this function reads in user commands &#039;live&#039; and checks if user wants to quit 
//if not, takes user input and converts it to char array compatible format(c-string)
//and prepares original commands array. Finally, checks if any types of pipe commands were entered
// and returns enum piperedirect as such
PipeRedirect parse_command(char**);

//executes commands without pipes and is instructed to wait if the amp_flag is still false
void exec_cmd(char**);

//prepares commands for run_pipelines function which requires the commands be in a set order
//depending on which specific pipe command is used. Also sets seperate array with pipe types
//and prepares integer for number of times run_piplines loop must iterate
void cmds_prep(char**, char**, char**);

//most complex function. Iterates through a loop and executes command depending on pipe
//type accordingly. Also handles pipe maintnenance(two pipes used) through each iteration
//accordingly by closing and duplicating relevant pipes
void run_pipelines(int, char**, char**);

//simple bool function which checks if the user entered the words &#039;quit&#039; or &#039;exit&#039;
bool check_quit(string);


bool checkfor_amp(string);

class which handles everything:
#include &quot;system_call.h&quot;

PipeRedirect parse_command(char** cmds) {
  
   // Assume no pipe or redirect will be found.
   PipeRedirect result = NEITHER;
   
   //initiate character used as the &#039;c-string&#039;
   char *cstr;
   
   //initiate string which will be read in as user arguments
   string str_cmd;
   
   //initiate integer to count number of arguments
   int num_of_args = 0;
   
   //while user is entering input
   while(cin &gt;&gt; str_cmd)
    {

        //check if user wants to quit
        if (check_quit(str_cmd))
        {
            //if true, print message and exit
            cout &lt;&lt; &quot;Till next time\n&quot;;
            exit(0);
        }

        //check for ampersand
        if (checkfor_amp(str_cmd))
        {
            amp_flag = true;
            break;
        }

        //define size of &#039;c-string&#039;, copy original argument into &#039;c-string&#039;,
        //and put &#039;c-string&#039; into current location in array
        cstr = new char[str_cmd.size()+1];
        strcpy(cstr, str_cmd.c_str());
        cmds[num_of_args] = cstr;

        num_of_args++;

        //if user hits return
        if (cin.get() == &#039;\n&#039;)
            break;


    }

    //loop through arguments and check for any typr of pipe command
    for (int i=0; i&quot;) == 0 &#124;&#124; strcmp(cmds[i], &quot;&lt;&quot;) == 0) 
    {
      // Pipe found!  
      result = PIPE_REDIRECT;
      break;
    }

  }

   //make last element in array NULL for execvp call
   cmds[num_of_args] = NULL;
   
   //return piperedirect
   return result;
}


void exec_cmd(char** cmds)
{

  //initiate integer for pid
  pid_t pid;

  //fork process
  pid = fork();

  //check for error in pid returned
  if (pid &lt; 0)
    perror(&quot;Error (pid &lt; 0)&quot;);

  // child process
  else if (pid == 0) 
  {
    
    //execute command and return error if execvp fails
    execvp(cmds[0], cmds);
    perror(&quot;execvp error&quot;);

  
  } 
  
  // parent process
  else if(!amp_flag)
    // only wait if no ampersand
    waitpid(pid, NULL, 0);

}

void cmds_prep(char** cmds,char** ordered_cmds,char** cmd_types)
{
    //initiate two integers, first for index(type_count) in cmd_types array, and second for number of commands
    int type_count = -1, num_cmds = 0;
    
    //initiate character which will be all user arguments(including pipe arguments) concatenated
    char *cmds_cat_final;
    
    //initiate string which will be used to concatenate arguments
    string cmds_cat = &quot;&quot;;
    
    //loop through arguments and concatenate
    for(int i = 0; i &lt; MAX_ARGS;i++)
    {
        if(cmds[i] != NULL)
        {
            cmds_cat += cmds[i];
            cmds_cat += &quot; &quot;;
        }
         
        //hit NULL so break out of loop
        else
            break;

    }

    //define size of final concatenated string, copy original string into final concatenated char,
    //and put result into first location in orginal commands array since this array will no longer
    //be used
    cmds_cat_final  = new char[cmds_cat.size()+1];
    strcpy(cmds_cat_final, cmds_cat.c_str());
    cmds[0] = cmds_cat_final;

    //loop through commands array to fill pipe type array
    for(int i = 0; i &lt; MAX_ARGS; i++)
    {
        //done, so break
        if(cmds[i] == NULL)
            break;
        
        //found pipe command
        else if (strcmp(cmds[i], &quot;&quot;) == 0)
            cmd_types[++type_count] = cmds [i];

        
    }

    //loop through pipe types array and order commands in the ordered_commands array accordingly
    //as well as count number of ordered_cmds elements
    for(int i = 0; i &quot;) == 0)
        {
            //seperate preceding section from pipe-type syntax and put in array
            ordered_cmds[i] = strsep(&amp;cmds[0], cmd_types[i]);
            num_cmds++;
        }
        
        //found an in_redirect which is a little more tricky since the order of 
        //arguments before and after the &quot;&lt;&quot; command need to be reversed so that
        //the name of the text file is put first so that the file contents can be
        //written to the pipe in the run_pipelines function
        else if (strcmp(cmd_types[i], &quot;&lt;&quot;) == 0)
        {
            //put section of arguments before the redirect command in the next
            //element of the ordered_cmds array
            ordered_cmds[i + 1] = strsep(&amp;cmds[0], cmd_types[i]);
            num_cmds++;
            
            //if there is another pipe-type command, then seperate the section
            //after the &quot;&lt;&quot; command and put it in the current element of the 
            //ordered_cmds array
            if(cmd_types[i + 1] != NULL)
            {
            ordered_cmds[i] = strsep(&amp;cmds[0], cmd_types[i + 1]);
            num_cmds++;
            }
            
            //else just put the rest of the arguments in current section
            //since all other arguments have already been seperated and taken out
            else
            {
              ordered_cmds[i] = cmds[0];
              cmds[0] = NULL;
            }

            //since handled two sections of commands, increment i
            i++;
        }
    }

    //call run_pipelines with the number of command sections, 
    //prepared array of arguments in correct order, and array of pipe-types
    run_pipelines(num_cmds, ordered_cmds, cmd_types);

}

void run_pipelines(int num_cmds, char** ordered_cmds,char** cmd_types)
{
    //initiate two chars, one used to read and write from a file, and another to hold
    //a single argument seperated by &quot; &quot; temporarely
    char buffer, *temp_cmd;

    //initiate two integer arrays, one for the old pipe, and one for the new pipe
    //and intiate two integers, one for the file reader, and one to count characters
    //written or ead
    int old_fds[2], new_fds[2], file, char_count;

    //initiate integer for pid
    pid_t pid;

    //loop through argument sections seperately and each time fork of
    //a child process to execute relative command section
    for(int i = 0; i  0) 
                          temp_cmds[++cmd_count] = temp_cmd;
                         
                 }
                 
            } while(strlen(ordered_cmds[i]) &gt; 0);

            //prepare last element as NULL for execvp function
            temp_cmds[++cmd_count] = NULL;

            //if there is a next commands section, make new pipe
            if( i  0)
                {
                    close(old_fds[1]);
                    dup2(old_fds[0], 0);
                    close(old_fds[0]);

                }

                //if their is a next commands section, close new pipe and
                //duplicate write part of new pipe
                if( i &lt; num_cmds - 1)
                {
                    close(new_fds[0]);
                    dup2(new_fds[1], 1);
                    close(new_fds[1]);
                }

                //if this is first time in loop
                if(i == 0)
                {
                    //if pipe-type is in_redirect, open file and write to new pipe
                    if(strcmp(cmd_types[i], &quot; 0)
                            write(1, &amp;buffer, 1);
                    }

                    //else if pipe-type was not in_redirect, then simply execute commands section
                    else
                    execvp(temp_cmds[0], temp_cmds);
                }
                
                //not first time in loop
                else
                {
                    //if pipe-type was &quot;&#124;&quot;, then execute commands section
                    if(strcmp(cmd_types[i - 1], &quot;&#124;&quot;) == 0 &#124;&#124; strcmp(cmd_types[i - 1], &quot;&quot;) == 0)
                    {
                        file = open(temp_cmds[0], O_WRONLY &#124; O_CREAT, 0666);

                        //while reading from pipe and end of pipe not reached, write to file
                        while((char_count = read(0, &amp;buffer, 1)) &gt; 0)
                            write(file, &amp;buffer, 1);
                    }
                }

               
                exit(0);
            }

            //parent process
            else
            {
                //if there was a prevoius commands section, close old pipe
                if(i &gt; 0)
                {
                    close(old_fds[0]);
                    close(old_fds[1]);
                }

                //if there is a next commands section, then set old pipe to new pipe
                if( i &lt; num_cmds - 1)
                {
                    old_fds[0] = new_fds[0];
                    old_fds[1] = new_fds[1];
                }

                //if in last loop iteration, then wait for process id
                if(i == num_cmds - 1)
                    waitpid(pid, NULL, 0);
            }
    }


}

bool check_quit(string str_cmd)
{

  for(int i = 0; i &lt; str_cmd.length(); i++)
     str_cmd[i] = tolower(str_cmd[i]);

  if(str_cmd == &quot;quit&quot; &#124;&#124; str_cmd == &quot;exit&quot;)
      return true;
  else
      return false;
}

bool checkfor_amp(string str_cmd)
{

  for(int i = 0; i &lt; str_cmd.length(); i++)
     if(str_cmd[i] == &#039;&amp;&#039;)
     {
         return true;
     }

         return false;
}</description>
		<content:encoded><![CDATA[<p>Again thanks tons to sarah for posting her code which came a long way in helping me in my shell project.</p>
<p>heres my version of the shell which handles multiple piping, in_redirects, and out_redirects</p>
<p>thanks again sarah!</p>
<p>main:</p>
<p>//import header file<br />
#include &#8220;system_call.h&#8221;</p>
<p>using namespace std;</p>
<p>int main() {</p>
<p>    //initialize three char array: one for original commands, and the next<br />
    //two if if a pipe function is used with first containing the commands<br />
    //in the correct order and the next contianing exactly which pipe type(|, )<br />
    char *cmds[MAX_ARGS], *ordered_cmds[MAX_ARGS], *cmd_types[MAX_ARGS];;</p>
<p>    //initialize enum pipe_redirect defined in the header file<br />
    PipeRedirect pipe_redirect;</p>
<p>    //while &#8220;C++_Shell&#8221; prompt<br />
    while (true) {</p>
<p>      cout &lt; &#8220;;<br />
      //immediately call parse_command function and return whther any pipes will be needed<br />
      pipe_redirect = parse_command(cmds);<br />
      //if pipes needed, call cmds_prep funtion to prepare two arrays for run_pipelines function<br />
      if (pipe_redirect == PIPE_REDIRECT)<br />
      cmds_prep(cmds, ordered_cmds, cmd_types);<br />
      //else execute commands with no pipes<br />
      else<br />
      exec_cmd(cmds);            </p>
<p>      //clear all respective arrays<br />
      for (int i=0; i&lt;MAX_ARGS; i++)<br />
      {<br />
        ordered_cmds[i] = NULL;<br />
        cmds[i] = NULL;<br />
        cmd_types[i] = NULL;<br />
      }</p>
<p>    } </p>
<p>    //let OS know evrything is<br />
    return 0;<br />
}</p>
<p>header file:</p>
<p>//include all librarys needed for system calls, string functions, and stream<br />
#include<br />
#include<br />
#include<br />
#include<br />
#include<br />
#include<br />
#include<br />
#include </p>
<p>using namespace std;</p>
<p>//initialize enum piperedirect which can be either PIPE_REDIRECT indicating piping will be used<br />
//or NEITHER<br />
enum PipeRedirect {PIPE_REDIRECT, NEITHER};</p>
<p>//initialize constant integer at 256 to be used for most array limits and in most loops<br />
const int MAX_ARGS = 256;</p>
<p>//initialize amp_flag and set to false<br />
static bool amp_flag = false;</p>
<p>//this function reads in user commands &#8216;live&#8217; and checks if user wants to quit<br />
//if not, takes user input and converts it to char array compatible format(c-string)<br />
//and prepares original commands array. Finally, checks if any types of pipe commands were entered<br />
// and returns enum piperedirect as such<br />
PipeRedirect parse_command(char**);</p>
<p>//executes commands without pipes and is instructed to wait if the amp_flag is still false<br />
void exec_cmd(char**);</p>
<p>//prepares commands for run_pipelines function which requires the commands be in a set order<br />
//depending on which specific pipe command is used. Also sets seperate array with pipe types<br />
//and prepares integer for number of times run_piplines loop must iterate<br />
void cmds_prep(char**, char**, char**);</p>
<p>//most complex function. Iterates through a loop and executes command depending on pipe<br />
//type accordingly. Also handles pipe maintnenance(two pipes used) through each iteration<br />
//accordingly by closing and duplicating relevant pipes<br />
void run_pipelines(int, char**, char**);</p>
<p>//simple bool function which checks if the user entered the words &#8216;quit&#8217; or &#8216;exit&#8217;<br />
bool check_quit(string);</p>
<p>bool checkfor_amp(string);</p>
<p>class which handles everything:<br />
#include &#8220;system_call.h&#8221;</p>
<p>PipeRedirect parse_command(char** cmds) {</p>
<p>   // Assume no pipe or redirect will be found.<br />
   PipeRedirect result = NEITHER;</p>
<p>   //initiate character used as the &#8216;c-string&#8217;<br />
   char *cstr;</p>
<p>   //initiate string which will be read in as user arguments<br />
   string str_cmd;</p>
<p>   //initiate integer to count number of arguments<br />
   int num_of_args = 0;</p>
<p>   //while user is entering input<br />
   while(cin &gt;&gt; str_cmd)<br />
    {</p>
<p>        //check if user wants to quit<br />
        if (check_quit(str_cmd))<br />
        {<br />
            //if true, print message and exit<br />
            cout &lt;&lt; &quot;Till next time\n&quot;;<br />
            exit(0);<br />
        }</p>
<p>        //check for ampersand<br />
        if (checkfor_amp(str_cmd))<br />
        {<br />
            amp_flag = true;<br />
            break;<br />
        }</p>
<p>        //define size of &#039;c-string&#039;, copy original argument into &#039;c-string&#039;,<br />
        //and put &#039;c-string&#039; into current location in array<br />
        cstr = new char[str_cmd.size()+1];<br />
        strcpy(cstr, str_cmd.c_str());<br />
        cmds[num_of_args] = cstr;</p>
<p>        num_of_args++;</p>
<p>        //if user hits return<br />
        if (cin.get() == &#039;\n&#039;)<br />
            break;</p>
<p>    }</p>
<p>    //loop through arguments and check for any typr of pipe command<br />
    for (int i=0; i&#8221;) == 0 || strcmp(cmds[i], &#8220;&lt;&quot;) == 0)<br />
    {<br />
      // Pipe found!<br />
      result = PIPE_REDIRECT;<br />
      break;<br />
    }</p>
<p>  }</p>
<p>   //make last element in array NULL for execvp call<br />
   cmds[num_of_args] = NULL;</p>
<p>   //return piperedirect<br />
   return result;<br />
}</p>
<p>void exec_cmd(char** cmds)<br />
{</p>
<p>  //initiate integer for pid<br />
  pid_t pid;</p>
<p>  //fork process<br />
  pid = fork();</p>
<p>  //check for error in pid returned<br />
  if (pid &lt; 0)<br />
    perror(&quot;Error (pid &lt; 0)&quot;);</p>
<p>  // child process<br />
  else if (pid == 0)<br />
  {</p>
<p>    //execute command and return error if execvp fails<br />
    execvp(cmds[0], cmds);<br />
    perror(&quot;execvp error&quot;);</p>
<p>  } </p>
<p>  // parent process<br />
  else if(!amp_flag)<br />
    // only wait if no ampersand<br />
    waitpid(pid, NULL, 0);</p>
<p>}</p>
<p>void cmds_prep(char** cmds,char** ordered_cmds,char** cmd_types)<br />
{<br />
    //initiate two integers, first for index(type_count) in cmd_types array, and second for number of commands<br />
    int type_count = -1, num_cmds = 0;</p>
<p>    //initiate character which will be all user arguments(including pipe arguments) concatenated<br />
    char *cmds_cat_final;</p>
<p>    //initiate string which will be used to concatenate arguments<br />
    string cmds_cat = &quot;&quot;;</p>
<p>    //loop through arguments and concatenate<br />
    for(int i = 0; i &lt; MAX_ARGS;i++)<br />
    {<br />
        if(cmds[i] != NULL)<br />
        {<br />
            cmds_cat += cmds[i];<br />
            cmds_cat += &quot; &quot;;<br />
        }</p>
<p>        //hit NULL so break out of loop<br />
        else<br />
            break;</p>
<p>    }</p>
<p>    //define size of final concatenated string, copy original string into final concatenated char,<br />
    //and put result into first location in orginal commands array since this array will no longer<br />
    //be used<br />
    cmds_cat_final  = new char[cmds_cat.size()+1];<br />
    strcpy(cmds_cat_final, cmds_cat.c_str());<br />
    cmds[0] = cmds_cat_final;</p>
<p>    //loop through commands array to fill pipe type array<br />
    for(int i = 0; i &lt; MAX_ARGS; i++)<br />
    {<br />
        //done, so break<br />
        if(cmds[i] == NULL)<br />
            break;</p>
<p>        //found pipe command<br />
        else if (strcmp(cmds[i], &quot;&#8221;) == 0)<br />
            cmd_types[++type_count] = cmds [i];</p>
<p>    }</p>
<p>    //loop through pipe types array and order commands in the ordered_commands array accordingly<br />
    //as well as count number of ordered_cmds elements<br />
    for(int i = 0; i &#8220;) == 0)<br />
        {<br />
            //seperate preceding section from pipe-type syntax and put in array<br />
            ordered_cmds[i] = strsep(&amp;cmds[0], cmd_types[i]);<br />
            num_cmds++;<br />
        }</p>
<p>        //found an in_redirect which is a little more tricky since the order of<br />
        //arguments before and after the &#8220;&lt;&quot; command need to be reversed so that<br />
        //the name of the text file is put first so that the file contents can be<br />
        //written to the pipe in the run_pipelines function<br />
        else if (strcmp(cmd_types[i], &quot;&lt;&quot;) == 0)<br />
        {<br />
            //put section of arguments before the redirect command in the next<br />
            //element of the ordered_cmds array<br />
            ordered_cmds[i + 1] = strsep(&amp;cmds[0], cmd_types[i]);<br />
            num_cmds++;</p>
<p>            //if there is another pipe-type command, then seperate the section<br />
            //after the &quot;&lt;&quot; command and put it in the current element of the<br />
            //ordered_cmds array<br />
            if(cmd_types[i + 1] != NULL)<br />
            {<br />
            ordered_cmds[i] = strsep(&amp;cmds[0], cmd_types[i + 1]);<br />
            num_cmds++;<br />
            }</p>
<p>            //else just put the rest of the arguments in current section<br />
            //since all other arguments have already been seperated and taken out<br />
            else<br />
            {<br />
              ordered_cmds[i] = cmds[0];<br />
              cmds[0] = NULL;<br />
            }</p>
<p>            //since handled two sections of commands, increment i<br />
            i++;<br />
        }<br />
    }</p>
<p>    //call run_pipelines with the number of command sections,<br />
    //prepared array of arguments in correct order, and array of pipe-types<br />
    run_pipelines(num_cmds, ordered_cmds, cmd_types);</p>
<p>}</p>
<p>void run_pipelines(int num_cmds, char** ordered_cmds,char** cmd_types)<br />
{<br />
    //initiate two chars, one used to read and write from a file, and another to hold<br />
    //a single argument seperated by &quot; &quot; temporarely<br />
    char buffer, *temp_cmd;</p>
<p>    //initiate two integer arrays, one for the old pipe, and one for the new pipe<br />
    //and intiate two integers, one for the file reader, and one to count characters<br />
    //written or ead<br />
    int old_fds[2], new_fds[2], file, char_count;</p>
<p>    //initiate integer for pid<br />
    pid_t pid;</p>
<p>    //loop through argument sections seperately and each time fork of<br />
    //a child process to execute relative command section<br />
    for(int i = 0; i  0)<br />
                          temp_cmds[++cmd_count] = temp_cmd;</p>
<p>                 }</p>
<p>            } while(strlen(ordered_cmds[i]) &gt; 0);</p>
<p>            //prepare last element as NULL for execvp function<br />
            temp_cmds[++cmd_count] = NULL;</p>
<p>            //if there is a next commands section, make new pipe<br />
            if( i  0)<br />
                {<br />
                    close(old_fds[1]);<br />
                    dup2(old_fds[0], 0);<br />
                    close(old_fds[0]);</p>
<p>                }</p>
<p>                //if their is a next commands section, close new pipe and<br />
                //duplicate write part of new pipe<br />
                if( i &lt; num_cmds &#8211; 1)<br />
                {<br />
                    close(new_fds[0]);<br />
                    dup2(new_fds[1], 1);<br />
                    close(new_fds[1]);<br />
                }</p>
<p>                //if this is first time in loop<br />
                if(i == 0)<br />
                {<br />
                    //if pipe-type is in_redirect, open file and write to new pipe<br />
                    if(strcmp(cmd_types[i], &quot; 0)<br />
                            write(1, &amp;buffer, 1);<br />
                    }</p>
<p>                    //else if pipe-type was not in_redirect, then simply execute commands section<br />
                    else<br />
                    execvp(temp_cmds[0], temp_cmds);<br />
                }</p>
<p>                //not first time in loop<br />
                else<br />
                {<br />
                    //if pipe-type was &#8220;|&#8221;, then execute commands section<br />
                    if(strcmp(cmd_types[i - 1], &#8220;|&#8221;) == 0 || strcmp(cmd_types[i - 1], &#8220;&#8221;) == 0)<br />
                    {<br />
                        file = open(temp_cmds[0], O_WRONLY | O_CREAT, 0666);</p>
<p>                        //while reading from pipe and end of pipe not reached, write to file<br />
                        while((char_count = read(0, &amp;buffer, 1)) &gt; 0)<br />
                            write(file, &amp;buffer, 1);<br />
                    }<br />
                }</p>
<p>                exit(0);<br />
            }</p>
<p>            //parent process<br />
            else<br />
            {<br />
                //if there was a prevoius commands section, close old pipe<br />
                if(i &gt; 0)<br />
                {<br />
                    close(old_fds[0]);<br />
                    close(old_fds[1]);<br />
                }</p>
<p>                //if there is a next commands section, then set old pipe to new pipe<br />
                if( i &lt; num_cmds &#8211; 1)<br />
                {<br />
                    old_fds[0] = new_fds[0];<br />
                    old_fds[1] = new_fds[1];<br />
                }</p>
<p>                //if in last loop iteration, then wait for process id<br />
                if(i == num_cmds &#8211; 1)<br />
                    waitpid(pid, NULL, 0);<br />
            }<br />
    }</p>
<p>}</p>
<p>bool check_quit(string str_cmd)<br />
{</p>
<p>  for(int i = 0; i &lt; str_cmd.length(); i++)<br />
     str_cmd[i] = tolower(str_cmd[i]);</p>
<p>  if(str_cmd == &quot;quit&quot; || str_cmd == &quot;exit&quot;)<br />
      return true;<br />
  else<br />
      return false;<br />
}</p>
<p>bool checkfor_amp(string str_cmd)<br />
{</p>
<p>  for(int i = 0; i &lt; str_cmd.length(); i++)<br />
     if(str_cmd[i] == &#039;&amp;&#039;)<br />
     {<br />
         return true;<br />
     }</p>
<p>         return false;<br />
}</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Anna</title>
		<link>http://www.3till7.net/2008/11/29/c-shell-with-forks-and-pipes/comment-page-1/#comment-398345</link>
		<dc:creator>Anna</dc:creator>
		<pubDate>Sun, 03 Oct 2010 04:19:30 +0000</pubDate>
		<guid isPermaLink="false">http://www.3till7.net/?p=1746#comment-398345</guid>
		<description>Hi, 
This is such a useful tutorial. I have just finished writing my shell (almost). I am having issues with redirecting input. I was searching online and came across this page. Great blog, great info and useful info. Good work!:)

Anna</description>
		<content:encoded><![CDATA[<p>Hi,<br />
This is such a useful tutorial. I have just finished writing my shell (almost). I am having issues with redirecting input. I was searching online and came across this page. Great blog, great info and useful info. Good work!:)</p>
<p>Anna</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: AnObfuscator</title>
		<link>http://www.3till7.net/2008/11/29/c-shell-with-forks-and-pipes/comment-page-1/#comment-380264</link>
		<dc:creator>AnObfuscator</dc:creator>
		<pubDate>Sat, 17 Apr 2010 18:24:15 +0000</pubDate>
		<guid isPermaLink="false">http://www.3till7.net/?p=1746#comment-380264</guid>
		<description>Hi, I also have had to write a shell in C++ for my OS class... mine is even more complex, though, because we had to support an arbitrarily high number of pipes, file input, and file output all at the same time... :-/

Thanks for posting your code, it was quite helpful in figuring out what my shell was doing wrong (piping is the bane of my existence...)

Just a note: the reason you have the infinite prompt loop in &quot;redirect_cmd&quot; is because the child process is an *exact* copy of the parent process, including the program counter, the execution stack and your &quot;main&quot;. So the child was continuing on past the end of the if block, forking another child process, returning to main, printing a prompt, and so on. The reason the call to &quot;exec&quot; fixed it is process overlaying, where the execution code of the process is replaced with the execution code of the exec&#039;d function. Thus, because &quot;echo&quot; calls exit, your process obeyed and exited. 

A better solution would be to simply call exit(0) there instead of exec.</description>
		<content:encoded><![CDATA[<p>Hi, I also have had to write a shell in C++ for my OS class&#8230; mine is even more complex, though, because we had to support an arbitrarily high number of pipes, file input, and file output all at the same time&#8230; :-/</p>
<p>Thanks for posting your code, it was quite helpful in figuring out what my shell was doing wrong (piping is the bane of my existence&#8230;)</p>
<p>Just a note: the reason you have the infinite prompt loop in &#8220;redirect_cmd&#8221; is because the child process is an *exact* copy of the parent process, including the program counter, the execution stack and your &#8220;main&#8221;. So the child was continuing on past the end of the if block, forking another child process, returning to main, printing a prompt, and so on. The reason the call to &#8220;exec&#8221; fixed it is process overlaying, where the execution code of the process is replaced with the execution code of the exec&#8217;d function. Thus, because &#8220;echo&#8221; calls exit, your process obeyed and exited. </p>
<p>A better solution would be to simply call exit(0) there instead of exec.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: daniel</title>
		<link>http://www.3till7.net/2008/11/29/c-shell-with-forks-and-pipes/comment-page-1/#comment-373234</link>
		<dc:creator>daniel</dc:creator>
		<pubDate>Fri, 26 Feb 2010 00:12:46 +0000</pubDate>
		<guid isPermaLink="false">http://www.3till7.net/?p=1746#comment-373234</guid>
		<description>Check this working pipe:

&lt;pre&gt;void pipe_cmd(char** cmd1, char** cmd2){
           int fds[2];
           pipe(fds);
	   pid_t pid1, pid2;

           // child process #1
           if (pid1 = fork() == 0) {
                dup2(fds[1], 1);
		close(fds[0]);
		close(fds[1]);
                execvp(cmd1[0], cmd1);
                perror(&quot;execvp failed&quot;);

                // child process #2
                } else if ((pid2 = fork()) == 0) {
                  dup2(fds[0], 0);

                  close(fds[1]);
                  execvp(cmd2[0], cmd2);
                  perror(&quot;execvp failed&quot;);


            } else {
    	close(fds[1]);

    	waitpid(pid1, NULL, 0);
	waitpid(pid2, NULL, 0);
    	
		}
}&lt;/pre&gt;</description>
		<content:encoded><![CDATA[<p>Check this working pipe:</p>
<pre>void pipe_cmd(char** cmd1, char** cmd2){
           int fds[2];
           pipe(fds);
	   pid_t pid1, pid2;

           // child process #1
           if (pid1 = fork() == 0) {
                dup2(fds[1], 1);
		close(fds[0]);
		close(fds[1]);
                execvp(cmd1[0], cmd1);
                perror("execvp failed");

                // child process #2
                } else if ((pid2 = fork()) == 0) {
                  dup2(fds[0], 0);

                  close(fds[1]);
                  execvp(cmd2[0], cmd2);
                  perror("execvp failed");

            } else {
    	close(fds[1]);

    	waitpid(pid1, NULL, 0);
	waitpid(pid2, NULL, 0);

		}
}</pre>
]]></content:encoded>
	</item>
	<item>
		<title>By: spring</title>
		<link>http://www.3till7.net/2008/11/29/c-shell-with-forks-and-pipes/comment-page-1/#comment-323052</link>
		<dc:creator>spring</dc:creator>
		<pubDate>Wed, 11 Feb 2009 10:48:27 +0000</pubDate>
		<guid isPermaLink="false">http://www.3till7.net/?p=1746#comment-323052</guid>
		<description>I tested the program it works well, but there is some problem when you use pipe. The program will crash if you try use pipe. I tried this cmd &quot;ls-ali &#124; more&quot; and it will show this message &quot;execvp error: No such file or directoy&quot; at the end. After that it will hanged.</description>
		<content:encoded><![CDATA[<p>I tested the program it works well, but there is some problem when you use pipe. The program will crash if you try use pipe. I tried this cmd &#8220;ls-ali | more&#8221; and it will show this message &#8220;execvp error: No such file or directoy&#8221; at the end. After that it will hanged.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Ravi</title>
		<link>http://www.3till7.net/2008/11/29/c-shell-with-forks-and-pipes/comment-page-1/#comment-322893</link>
		<dc:creator>Ravi</dc:creator>
		<pubDate>Tue, 10 Feb 2009 00:20:11 +0000</pubDate>
		<guid isPermaLink="false">http://www.3till7.net/?p=1746#comment-322893</guid>
		<description>In your code you are saving the file to you local directory. Is there anyway to save it on host computer?</description>
		<content:encoded><![CDATA[<p>In your code you are saving the file to you local directory. Is there anyway to save it on host computer?</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Rebecca</title>
		<link>http://www.3till7.net/2008/11/29/c-shell-with-forks-and-pipes/comment-page-1/#comment-312522</link>
		<dc:creator>Rebecca</dc:creator>
		<pubDate>Wed, 03 Dec 2008 22:51:19 +0000</pubDate>
		<guid isPermaLink="false">http://www.3till7.net/?p=1746#comment-312522</guid>
		<description>Not only is it awesome you&#039;re releasing this, but including tons of comments! Thanks a lot :) 

I plan to take an OS course at some point (CS degree ftw) and I&#039;ll bookmark this for then :P

I really like the &quot;SarahShell&gt;&quot; haha :)</description>
		<content:encoded><![CDATA[<p>Not only is it awesome you&#8217;re releasing this, but including tons of comments! Thanks a lot :) </p>
<p>I plan to take an OS course at some point (CS degree ftw) and I&#8217;ll bookmark this for then :P</p>
<p>I really like the &#8220;SarahShell&gt;&#8221; haha :)</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: tuple</title>
		<link>http://www.3till7.net/2008/11/29/c-shell-with-forks-and-pipes/comment-page-1/#comment-311582</link>
		<dc:creator>tuple</dc:creator>
		<pubDate>Sun, 30 Nov 2008 06:27:22 +0000</pubDate>
		<guid isPermaLink="false">http://www.3till7.net/?p=1746#comment-311582</guid>
		<description>Thats very nice of you to release this under GPL.

This will undoubtedly be useful to many. A common program which runs under both windows and unix will also be of much value. :)</description>
		<content:encoded><![CDATA[<p>Thats very nice of you to release this under GPL.</p>
<p>This will undoubtedly be useful to many. A common program which runs under both windows and unix will also be of much value. :)</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Jem</title>
		<link>http://www.3till7.net/2008/11/29/c-shell-with-forks-and-pipes/comment-page-1/#comment-311487</link>
		<dc:creator>Jem</dc:creator>
		<pubDate>Sat, 29 Nov 2008 20:05:51 +0000</pubDate>
		<guid isPermaLink="false">http://www.3till7.net/?p=1746#comment-311487</guid>
		<description>I have a C++ book on my bookshelf. One day I shall read it, and know what you&#039;re on about. For now, I shall nod and agree. ;)</description>
		<content:encoded><![CDATA[<p>I have a C++ book on my bookshelf. One day I shall read it, and know what you&#8217;re on about. For now, I shall nod and agree. ;)</p>
]]></content:encoded>
	</item>
</channel>
</rss>

