在C 中,当CIN为Bash Heredoc时,请致电叉会导致反复的输入片段



我正在在C 中实现类似壳的程序。它的循环从CIN,叉子上读取,并等待孩子。

如果输入是互动的,则可以从另一个程序进行管道。但是,当输入是bash heredoc时,该程序会重读输入的一部分(有时无限期)。

我了解子过程继承了父母的文件描述符,包括共享文件偏移。但是,在此示例中,孩子没有从CIN上读取任何内容,因此我认为它不应该触及偏移。我对为什么会发生这种情况感到困惑。


test.cpp:

#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char **argv)
{
    std::string line;
    while (std::getline(std::cin, line)) {
        pid_t pid = fork();
        if (pid == 0) { // child
            break; // exit immediately
        }
        else if (pid > 0) { // parent
            waitpid(pid, nullptr, 0);
        }
        else { // error
            perror("fork");
        }
        std::cout << getpid() << ": " << line << "n";
    }
    return 0;
}

我将其编译如下:

g++ test.cpp -std=c++11

然后我用:

运行它
./a.out <<EOF
hello world
goodbye world
EOF

输出:

7754: hello world
7754: goodbye world
7754: goodbye world

如果我将第三行foo bar添加到输入命令中,则该程序陷入了无限循环:

13080: hello world
13080: goodbye world
13080: foo bar
13080: o world
13080: goodbye world
13080: foo bar
13080: o world
[...]

版本:

  • linux内核:4.4.0-51总生成
  • ubuntu:16.04.1 lts(Xenial)
  • bash:gnu bash,版本4.3.46(1)-Release(x86_64-pc-linux-gnu)
  • GCC:G (Ubuntu 5.4.0-6ubuntu1〜16.04.4)5.4.0 20160609

我能够复制此问题,不仅使用Heredoc,而且还使用标准文件重定向。

这是我使用的测试脚本。在第一个和第二种情况下,我都得到了第二行输入的重复。

./a.out < Input.txt
echo
cat Input.txt | ./a.out
echo
./a.out <<EOF
hello world
goodbye world
EOF

在孩子退出之前关闭stdin似乎消除了两个问题。

#include <iostream>
#include <sstream>
#include <unistd.h>
#include <sys/wait.h>
#include <limits>
int main(int argc, char **argv)
{
    std::string line;
    while (std::getline(std::cin, line)) {
        pid_t pid = fork();
        if (pid == 0) { // child
            close(STDIN_FILENO);
            break; // exit after first closing stdin
        }
        else if (pid > 0) { // parent
            waitpid(pid, nullptr, 0);
        }
        else { // error
            perror("fork");
        }
        std::cout << getpid() << ": " << line << "n";
    }
    return 0;
}

相关内容

  • 没有找到相关文章

最新更新