I am implementing a shell-like program in C++. It has a loop that reads from cin, forks, and waits for the child.
This works fine if the input is interactive or if it's piped from another program. However, when the input is a bash heredoc, the program rereads parts of the input (sometimes indefinitely).
I understand that the child process inherits the parent's file descriptors, including shared file offset. However, the child in this example does not read anything from cin, so I think it shouldn't touch the offset. I'm kind of stumped about why this is happening.
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;
}
I compile it as follows:
g++ test.cpp -std=c++11
Then I run it with:
./a.out <<EOF
hello world
goodbye world
EOF
Output:
7754: hello world
7754: goodbye world
7754: goodbye world
If I add a third line foo bar
to the input command, the program gets stuck in an infinite loop:
13080: hello world
13080: goodbye world
13080: foo bar
13080: o world
13080: goodbye world
13080: foo bar
13080: o world
[...]
Versions:
- Linux kernel: 4.4.0-51-generic
- Ubuntu: 16.04.1 LTS (xenial)
- bash: GNU bash, version 4.3.46(1)-release (x86_64-pc-linux-gnu)
- gcc: g++ (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609