Implementing Pipes in a C shell (Unix)

2020-02-12 08:44发布

Basically I have created a shell using standard POSIX commands, I want to be able to Implement Piping as well. Right now it handles commands correctly, and can do background processing with &. But I need to be able to pipe using | and >> as well. For example something like this: cat file1 file2 >> file3 cat file1 file2 | more more file1 | grep stuff

Here is the code I have currently. I also want to AVOID "SYSTEM" calls. I know U need to use dup2, but the way I did my code is a bit odd, so im hoping if someone can tell me if it is feasible to implement pipes in this code? thanks! I know dup2 is used, but also im def. confused at how to implement >> as WELL as |

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

using namespace std;


void Execute(char* command[],bool BG)
{
//Int Status is Used Purely for the waitpid, fork() is set up like normal.
    int status;
    pid_t pid = fork();


    switch(pid)
    {
        case  0:
            execvp(command[0], command);

            if(execvp(command[0], command) == -1)
            {
                cout << "Command Not Found" << endl;
                exit(0);
            }

          default:
            if(BG == 0)
            {
                    waitpid(pid, &status, 0);
//Debug             cout << "DEBUG:Child Finished" << endl;
            }


    }

}


bool ParseArg(char* prompt, char* command[], char Readin[],bool BG)
{

    fprintf(stderr, "myshell>");
        cin.getline(Readin,50);
    prompt = strtok(Readin, " ");
    int i = 0;

    while(prompt != NULL)
    {
        command[i] = prompt;
        if(strcmp(command[i], "&") == 0){
//Debug        cout << "& found";
        command[i] = NULL;
        return true;
    }
//Debug        cout << command[i] << " ";
        i++;
        prompt = strtok(NULL, " ");

    }
    return false;
}

void Clean(char* command[])
{
//Clean Array
        for(int a=0; a < 50; a++)
        {
             command[a] = NULL;
        }
}



int main()
{
   char* prompt;
   char* command[50];
   char Readin[50]; 
   bool BG = false;



   while(command[0] != NULL)
   {

        Clean(command);
       BG = ParseArg(prompt, command, Readin, BG);
       if(strcmp(command[0], "exit") == 0 || strcmp(command[0], "quit") == 0 )
       {
             break;
       }

    else
    {
            Execute(command,BG);
    }

   }

   return 1;

}

标签: c unix shell pipe
2条回答
女痞
2楼-- · 2020-02-12 09:27

You should be able to implement pipes and output redirection with your shell, but there are a few things I noticed:

  • Your code for reading input, parsing, and output are mixed together, you may want to separate this functionality.
  • strtok won't work very well as a parser for shell commands. It will work for very simple commands, but you may want to look into creating or finding a better parser. A command like echo "hello world" will be problematic with your current parsing method.
  • You may want to create a simple structure for holding your parsed commands.

Here is some pseudocode to get you started:

#define MAX_LINE 10000
#define MAX_COMMANDS 100
#define MAX_ARGS 100

// Struct to contain parsed input
struct command
{
    // Change these with IO redirection
    FILE *input; // Should default to STDIN
    FILE *output; // Should default to STDOUT

    int num_commands;
    int num_args[MAX_COMMANDS]; // Number of args for each command
    char* command_list[MAX_COMMANDS]; // Contains the programs to be run
    char* args_list[MAX_COMMANDS][MAX_ARGS]; // The args for each command
    boolean background_task;
    boolean append;
}

int main()
{
    char input[MAX_LINE];

    while (1)
    {
        struct command cmd;

        print_prompt();
        read_input(input);
        parse_input(input, &cmd);
        execute(&cmd);
    }
}

Good luck with this project!

查看更多
淡お忘
3楼-- · 2020-02-12 09:33

Pipes and redirections are different, actually. To implement a redirection (such as >>) you have to use dup2 indeed. First, open the desired file with appropriate flags (for >> they'll be O_WRONLY|O_CREAT|O_APPEND). Second, using dup2, make stdout (file descriptor 1) a copy of this newly opened fd. Finally, close newly opened fd.

To create a pipe, you'll need a pipe syscall. Read its manpage, it contains example code. Then you'll also need dup2 to make file descriptors returned by pipe be stdin for one process and stdout for another, respectively.

查看更多
登录 后发表回答