在 C shell 中实现管道 (Unix)

发布于 2024-11-05 02:17:45 字数 2238 浏览 1 评论 0原文

基本上我已经使用标准 POSIX 命令创建了一个 shell,我也希望能够实现管道。现在它可以正确处理命令,并且可以使用 & 进行后台处理。但我需要能够使用 | 进行管道传输和>>以及。 例如这样的事情: cat 文件1 文件2>>文件3 猫 文件1 文件2 |更多的 更多文件1 | grep stuff

这是我目前的代码。我还想避免“系统”调用。我知道你需要使用 dup2,但是我的代码的方式有点奇怪,所以我希望有人能告诉我在这段代码中实现管道是否可行?谢谢!我知道使用了 dup2,但我也知道。不知道如何实现>>以及 |

#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;

}

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;

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

打小就很酷 2024-11-12 02:17:45

实际上,管道和重定向是不同的。要实现重定向(例如>>),您确实必须使用dup2。首先,使用适当的标志打开所需的文件(对于>>,它们将为O_WRONLY|O_CREAT|O_APPEND)。其次,使用 dup2 使 stdout(文件描述符 1)成为这个新打开的 fd 的副本。最后关闭新打开的fd。

要创建管道,您需要一个pipe系统调用。阅读它的联机帮助页,它包含示例代码。然后,您还需要 dup2 使 pipe 返回的文件描述符分别成为一个进程的标准输入和另一个进程的标准输出。

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.

三生池水覆流年 2024-11-12 02:17:45

您应该能够使用 shell 实现管道和输出重定向,但我注意到以下几点:

  • 用于读取输入、解析和输出的代码混合在一起,您可能希望分离此功能。
  • strtok 作为 shell 命令的解析器不能很好地工作。它适用于非常简单的命令,但您可能想考虑创建或寻找更好的解析器。像 echo "hello world" 这样的命令对于您当前的解析方法来说将会出现问题。
  • 您可能想要创建一个简单的结构来保存已解析的命令。

这里有一些伪代码可以帮助您入门:

#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);
    }
}

祝这个项目好运!

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!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文