C++ microshell,输入一个命令并使用fork(),dup(),pipe()将其通过管道传输到进程。只是我没有得到我想要的结果


#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <sstream>
#include <stdlib.h>
#include <sys/utsname.h>
#include <unistd.h>

using namespace std;
//first comannd to execute
void first(int pipeA[], char * command[]){
  //redirect STDOUT to pipe[1] and close the pipe[0] we are not using
  dup2(pipeA[1], 1);
  close(pipeA[0]);
  execvp(command[0], command);
  printf(" first error ");
  exit(127);
}
void second(int pipeA[], char * command2[]){
  //redirect STDIN to pipe[0] and close the pipe[1] that we are not using
  dup2(pipeA[0], 0);
  close(pipeA[1]);
  //This doesnt seem to be doing anything at times
  execvp(command2[0], command2);
  perror(" second error ");
  exit(127);
}

int main(void)
{
  char buf[1024];
  char * command[1024];// this one is the first input usually 'cat file.txt'
  //Use only one or the other, sort never works and 'grep U' works sometimes
  char * command2[] = {(char *)"sort", (char *) NULL};// this is wants to sort the above 'command[1024]' and its use in the second function
  //char * command2[] = {(char *)"grep",(char *)"U",(char *) NULL};// this is wants to grep the above 'command[1024]' and its use in the second function
  //variables for forks and waits
  pid_t pid;
  pid_t pid2;
  int  status;
  int  status2;
  //see if || exists not in use currently
  bool pipeExists = false;
  //create pipe
  int pipeA[2];
  pipe(pipeA);
  //first line and ask for input,
  cout<< "command: ";
  while (fgets(buf,1024,stdin) != NULL)
 {
    buf[strlen(buf) -1] = 0; 
    //Save input into buf and tokenized? it
    //NOT YET CATCHING ||, im only debugging and usually use use 'cat file.txt'
    int number =0;
    char * ptr;
    ptr = strtok(buf, " ");
    while(ptr != NULL){
        command[number] = ptr;
        ptr = strtok(NULL, " ");
        number++;
    }
    //***************************************************************
    //1. do the pipes go here or after the children?
    //They seem to be working here but im not really sure where they should be
    close(pipeA[0]);
    close(pipeA[1]);
   //create first child
   if ((pid = fork()) <0)
    printf("fork error");
   else if (pid == 0) 
    { /* child */
        //create second child INSIDE ORIGINAL CHILD
        //2. Is this correct? or is there not supposed to be grandchildren?
        if ((pid2 = fork()) <0)
        printf("fork 2 error");
        else if (pid == 0) 
        { /* child */
         second(pipeA, command2);
         printf("couldn't execute: %s");
         exit(127);
        }

        //first command from buf
         first(pipeA, command);
         printf("couldn't execute: %s");
         exit(127);

        //3. Do I wait for this child aswell? 
        if ( (pid2 = waitpid(pid2, &status2, 0)) < 0)
          printf("waitpid error");
    }

   /* parent */ 
   if ( (pid = waitpid(pid, &status, 0)) < 0)
    printf("waitpid error");  
   printf("Command :");
   //***************************************************************
   //***************************************************************
   //SECOND WAY OF DOING IT
   // THIS WAY IT TRIGGERS WAITPID ERRORS.
   /*
    close(pipeA[0]);
    close(pipeA[1]);
   //create first child
   if ((pid = fork()) <0)
    printf("fork error");
   else if (pid == 0) 
    { 
     first(pipeA, command);
     printf("couldn't execute: %s");
     exit(127);
    }
    //create second child INSIDE ORIGINAL CHILD
    if ((pid2 = fork()) <0)
    printf("fork 2 error");
    else if (pid == 0) 
    { 
     second(pipeA, command2);
     printf("couldn't execute: %s");
     exit(127);
    }
    //3. Do I wait for this child aswell? 
    if ( (pid2 = waitpid(pid2, &status2, 0)) < 0)
      printf("waitpid error");

     if ( (pid = waitpid(pid, &status, 0)) < 0)
      printf("waitpid error");  
     printf("Command :");
   */
   //***************************************************************
 }
   exit(0);
} 

几乎可以在这里提出的问题显示的内容。

我需要创建一个Microshell,该微壳接收命令(" cat file.txt"),并使用execvp()执行它,然后将其输送到另一个过程,然后"排序"或" grep u"或任何其他过程。

这只是我的过程无法正确运行或无法显示任何内容。我到处都关闭了管道,什么也没发生。

op。

解决方案

这是适用于Microshell的代码。

我最终在原始父母过程中创建了两个过程。

将一些变量移入时循环中并重置它们再次工作。还要每次运行并关闭管道时创建管道。

为两个过程创建了一个waitpid(),而不仅仅是一个。

#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <sstream>
#include <stdlib.h>
#include <sys/utsname.h>
#include <unistd.h>
using namespace std;

//This function will execute the users first command.
//It takes in a pipe the command array and a boolean to check for piping
//If a pipe exists then the boolean is true and will dup() the STDOUT into the write part of the pipe
//We close unecessary parts of the pipe and execvp() the command in the command array
//there it some error checkink in case the command doesn't execute
void first_command(int pipeA[], char * command[], bool pipeExists){
  if(pipeExists){
    dup2(pipeA[1], 1);
    close(pipeA[0]);
  }
  execvp(command[0], command);
  printf("can not execute first command. n");
  exit(127);
}
//This function is only called in the main is a piping exists
//It takes in a pipe and a command array
//It dup() the STDIN from the read end of the pipe and closes the unsued end
//It will execute the command accorind to what was provided in the the pipe
void second_command(int pipeA[], char * command2[]){
  dup2(pipeA[0], 0);
  close(pipeA[1]);
  execvp(command2[0], command2);
  printf("can not execute second command. n");
  exit(127);
}

int main(void)
{
  //this variable will take in the line of input submitted by the user
  char buf[1024];
  //PIDs for the two child processes
  pid_t pid;
  pid_t pid2;
  //these will be use to check the status of each child in the parent process
  int  status;
  int  status2;
  //initializes the pipe
  int pipeA[2];
  //out put the first line to ask user for input
  cout<< "480shel> ";
  //stay inside the loop and keep asking the user for input until the user quits the program
  while (fgets(buf,1024,stdin) != NULL){
    //initialize a boolean to check if user wants to pipe something, set to false by default until we check with user
    bool pipeExists = false;
    //initialize this arrays to NULL so anything that store in them gets cleared out.
    //these arrays will hold the commands that the user wants to carry out.
    char * command[1024] = {NULL, NULL, NULL};
    char * command2[1024] = {NULL, NULL, NULL};
    //Important to delete mark the last byte as 0 in our input
    buf[strlen(buf) -1] = 0;
    //initialize this number to zero to start save the tokens at this index 
    int index = 0;
    //a char * to hold the token saved by strtok
    char * ptr;
    ptr = strtok(buf, " ");
    //Loop through 'buf' and save tokens accordingly
    while(ptr != NULL){
      //If ptr is equal to q or quit then user want to exit program
      if(strcmp( ptr, "q" ) == 0){
        exit(0);
      }
      if(strcmp( ptr, "quit" ) == 0){
        exit(0);
      }
      //if ptr is equal to || user wants to pipe something and we change pipeExists to true
      if(strcmp( ptr, "||" ) == 0){
        pipeExists = true;
        index= 0;
        ptr = strtok(NULL, " ");
      }
      //enter here while user doesnt want to user pipes
      if(!pipeExists){
        command[index] = ptr;
        ptr = strtok(NULL, " ");
        index++;
      }
      //enter here if user want to use pipes
      if(pipeExists){
        command2[index] = ptr;
        ptr = strtok(NULL, " ");
        index++;
      }
    }
    //if pipes exists then initialize it
    if(pipeExists){
      pipe(pipeA);
    }
    //create first child
    if ((pid = fork()) == 0) {
      //pass in the pipe, commands and pipe to function to execute
      first_command(pipeA, command, pipeExists);
    }
    else if(pid < 0){
      //error with child
      cerr<<"error forking first child"<<endl;
    }
    // if pipe exists create a second process to execute the second part of the command
    if(pipeExists){
      //create second child 
      if ((pid2 = fork()) == 0) {
        second_command(pipeA, command2);
      }
      else if(pid2 < 0){
        //error with second child
        cerr<<"error forking second child"<<endl;
      }
    }
    //if the pipe was created then we close its ends
    if(pipeExists){
      close(pipeA[0]);
      close(pipeA[1]);
    }
    //wait for the first child that ALWAYS executes
    if ( (pid = waitpid(pid, &status, 0)) < 0)
      cerr<<"error waiting for first child"<<endl;
    //wait for the second child bu only if user wanted to created to use piping
    if(pipeExists){
      if ( (pid2 = waitpid(pid2, &status2, 0)) < 0)
        cerr<<"error waiting for second child"<<endl;
    }

    cerr<<"480shell> ";
  }//endwhile
  exit(0);
} 

最新更新