c++ - 在 C++ : Why is a blank line entering getline after piping? 中编码管道 "|"

标签 c++ pipe fork getline dup2

我正在编写模拟 shell,目前正在使用 dup2 编写管道代码。这是我的代码:

bool Pipe::execute() {
    int fds[2]; //will hold file descriptors
    pipe(fds);
    int status;
    int errorno;
    pid_t child;
    child = fork();

    if (-1 == child) {
        perror("fork failed");
    }
    if (child == 0) {
        dup2(fds[1], STDOUT_FILENO);
        close(fds[0]);
        close(fds[1]);
        this->component->lchild->execute();
        _exit(1);
    }
    else if (child > 0) {
        dup2(fds[0], STDIN_FILENO);
        close(fds[0]);
        close(fds[1]);
        this->component->rchild->execute();
        waitpid(child, &status, 0);
        if ( WIFEXITED(status) ) {
            //printf("child exited with = %d\n",WEXITSTATUS(status));
            if ( WEXITSTATUS(status) == 0) {
                cout << "pipe parent finishing" << endl;
                return true;
            }
        }
        return false;
    }
}

this->component->lchild->execute();this->component->rchild->execute();运行 execvp在相应的命令上。我已经通过在父进程中打印出一条语句来确认每一个都返回了。然而,在我的Pipe::execute() ,似乎子进程没有完成,因为从未打印父进程中的 cout 语句,并且在提示 ( $) 初始化后出现段错误(见图)。这是每次执行后初始化提示的主要功能:

int main()
{
    Prompt new_prompt;
    while(1) {
        new_prompt.initialize();
    }
    return 0;
}

这里是 initialize()功能:

void Prompt::initialize()
{
    cout << "$ ";
    std::getline(std::cin, input);

    parse(input);
    run();
    input.clear();
    tokens.clear();
    fflush(stdout);
    fflush(stdin);
    return;
}

好像ls | sort运行正常,但是当提示被初始化时,一个空行被 getline 读入输入。我试过使用 cin.clear()、cin.ignore 以及上面的 fflush 和 clear() 行。这个空白字符串被“解析”,然后是 run()函数被调用,它试图解引用一个空指针。关于为什么/在哪里将此空白行输入到 getline 中的任何想法?我该如何解决这个问题?谢谢!

更新:管道中的父进程现在正在完成。我还注意到我的 I/O 重定向类( >< )也遇到段错误。我认为我没有正确刷新流或关闭文件描述符...

这是我的 execute() lchild 和 rchild 的函数:

bool Command::execute() {
    int status;
    int errorno;
    pid_t child;
    vector<char *> argv;
    for (unsigned i=0; i < this->command.size(); ++i) {
        char * cstr = const_cast<char*>(this->command.at(i).c_str());
        argv.push_back(cstr);
    }
    argv.push_back(NULL);
    child = fork();
    if (-1 == child) {
        perror("fork failed");
    }
    if (child == 0) {
        errorno = execvp(*argv.data(), argv.data());
        _exit(1);

    } else if (child > 0) {
        waitpid(child, &status, 0);
        if ( WIFEXITED(status) ) {
            //printf("child exited with = %d\n",WEXITSTATUS(status));
            if ( WEXITSTATUS(status) == 0) {
                //cout << "command parent finishing" << endl;
                return true;
            }
        }
        return false;
    }
}

最佳答案

这是错误:

else if (child > 0) {
    dup2(fds[0], STDIN_FILENO);
    close(fds[0]);
    close(fds[1]);
    this->component->rchild->execute();

您正在为 parent 关闭 stdin,而不仅仅是正确的 child 。在此之后,父进程的标准输入与右子进程的标准输入相同。

之后

std::getline(std::cin, input);

尝试读取左 child 的输出,而不是原始的标准输入。到那时,左边的 child 已经完成,管道的那一端已经关闭。这使得读取 stdin 失败,并使 input 保持其原始状态不变。

编辑:您的设计有一个小缺陷和一个大缺陷。小缺陷是您不需要 Pipe::execute 中的分支。主要缺陷是 child 应该是重定向流并关闭描述符的人。

只需通过 fork() 传递输入和输出参数,让 child dup2 这些。不要忘记让它也关闭不相关的管端。如果你不这样做,左 child 将完成但它的输出管道将继续存在于其他进程中。只要该描述符的其他拷贝存在,正确的 child 在读取其管道末端时永远不会得到 EOF - 并且永远是周 block 。

关于c++ - 在 C++ : Why is a blank line entering getline after piping? 中编码管道 "|",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55214615/

相关文章:

python - ffmpeg - 在内存而不是磁盘中输出图像

c++ - .get() 重复计算文件末尾的字符

c++ - 编译时出现错误 "fopen' : This function or variable may be unsafe.

Python os.pipe 与 multiprocessing.Pipe

c - popen() 的安全版本?

c - fork() 反复失败

c++ - 如何制作多语言QT UI应用程序?

c++ - 降低算法的时间复杂度

c - 了解 fork()、sleep() 和进程通量

c# - C# 中的 fork 概念