簡體   English   中英

如何在 Z6CE809EACF90BA125B40FA4BD90392 中執行來自 linux shell 的 pipe 命令?

[英]how to implement pipe command from linux shell in c++?

我正在一個項目中實施一個迷你 linux shell,我想實施一個command1 | command2命令,它基本上是這樣工作的: command1 | command2 : 使用 pipe 字符“ | ” 將生成 pipe,將 command1 stdout 重定向到其寫入通道,將 command2 stdin 重定向到其讀取通道。

或者:

command1 |& command2 :使用 pipe 字符“ |& ”將生成 pipe,將 command1 stderr 重定向到管道的寫入通道,將 command2 stdin 重定向到管道的讀取通道。

現在命令 1 可以是我使用 execv 運行的 linux 的外部命令,也可以是我編寫的內置命令,並且 command2 始終是外部命令

我的代碼不能正常工作,我不知道問題到底出在哪里,因為我實現了許多命令,並且它們都工作得很好,例如(cp,重定向......),所以我的代碼中的基礎很好,但是pipe 是錯誤的:例如,如果命令是: showpid |./parser.exe 1其中 parser.exe 是對命令進行解析的給定文件,例如這里如果 showpid 打印: shell process pid is 12311 ,此命令showpid |./parser.exe 1 output 應該是"shell" ,但在我的代碼中 output 是shell process pid is 12311

這是我的 pipe 命令實現:

這是 pipe 命令的 class :

class PipeCommand : public Command {
private:
    int pipeNum;
    int split;
    string cmd1;
    string cmd2;
public:
    PipeCommand(const char* cmd_line);
    virtual ~PipeCommand() {}
    void execute() override;
};

// the pipe constructor , here i want to extract each command from the right and left side of the pipe from the cmd_line , which  is the command line that i get
// fro example : " showpid | grep 1 "

PipeCommand::PipeCommand(const char* cmd_line):Command(cmd_line) {
    pipeNum = -1;
    isBackground = _isBackgroundComamnd(cmd_line);
    string cmd1 = "", cmd2 = "";
    int split = -1;
    for (int i = 0; i < this->num_args; i++) {
        if (strcmp(args[i], "|") == 0) {
            split = i;
            pipeNum = 1;

            break;
        }

        if (strcmp(args[i], "|&") == 0) {
            split = i;
            pipeNum = 2;
            break;
        }

    }


    for (int i = 0; i < split; i++) {
        cmd1 = cmd1 + args[i] + " ";
    }

    for (int i = split + 1; i < num_args; i++) {
        cmd2 = cmd2 + args[i] + " ";
    }


// the implementation of the pipe command
void PipeCommand::execute() {

    int pipeFd[2];
    int pid;
    pipe(pipeFd);

    pid = fork();
    if (pid == 0) { // child process .

    close(pipeFd[1]);
    dup2(pipeFd[1], pipeNum);


        if (isBuiltInCMD(args[0])) {   // if the command is built in which means i wrote it i run it like this ( this works fine i checked it)
            Command *newCmd = CreateBuiltInCommand(const_cast<char *>(cmd1.c_str()));
            newCmd->execute();
            exit(0);
        } else { // if the command is external than use execv
            const char **argv = new const char *[4];
            argv[0] = "/bin/bash";
            argv[1] = "-c";
            argv[2] = cmd1.c_str();
            argv[3] = nullptr;
            execv(argv[0], const_cast<char **>(argv));
            perror("execvp failed");

        } 
    } else {     // the parent process , basically runs the command2 , which it can be only an external command
        pid = fork();  // we fork again in the parent process

        if (pid == 0)  {      // the child process executes the secomd command using execv

            dup2(pipeFd[0], STDIN_FILENO);


        close(pipeFd[0]); 
        dup2(pipeFd[0], pipeNum); 

            // execute

                const char **argv = new const char *[4];
                argv[0] = "/bin/bash";
                argv[1] = "-c";
                argv[2] = cmd2.c_str();
                argv[3] = nullptr;
                execv(argv[0], const_cast<char **>(argv));
                perror("execvp failed");
                             
        } else {   // the parent process waits 

            waitpid(pid,NULL,0);
            close(pipeFd[1]);
            close(pipeFd[0]);
        }

    }
}

我認為您應該查看關閉/復制文件描述符的順序。 具體來說:

第一個命令需要使用現有的標准輸入 (fd 0)。 不要關閉它。 但是您應該關閉現有的標准輸出(fd 1),然后執行 fd dup 使其變為 1。

第二個命令以另一種方式執行。

我會用一個更簡單的例子來測試。 讓管道工作,然后做 exec 的事情。


這是稍后添加的編輯信息。

在 C/C++ 世界中,程序啟動時有 3 個標准文件:

FD 0 是標准輸入 -- 用於輸入 FD 1 是標准輸出 -- 用於正常 output FD 2 是標准錯誤 -- 用於錯誤 output

當你這樣做時:

grep foo < file.txt | grep條

shell 所做的是:

- 是否調用 pipe 來獲取輸入和 output 文件 - 在第一個 grep 上用於 foo,關閉 fd 0 (stdin) 並打開文件。 它將落在 0 上,因此是 grep 命令的標准輸入。 -關閉stdout並將其分配給pipe的out部分

在第二個 grep 上:

-關閉 1 (stdin) -並將 pipe 輸入部分移動到 1,以便設置標准輸入。

因此,最后:

第 1 部分 fd 0 (stdin) 是文件 第 1 部分 fd 1 (stdout) 是 pipe 的 output 部分 第 2 部分 fd 0 (stdin) 是 Z20826A3CB514DBCFE4E5C9Z 的輸入部分

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM