Here is an example code that shows the issue I have:
#!/bin/bash
counter() {
seq 1000 | while read NUM; do
echo $NUM
echo "debug: $NUM" >&2
sleep 0.1 # slow it down so we know when this loop really ends
done
}
counter | grep --line-buffered "[27]" | head -n1
If I understand it correctly, "head" finishes on the first match (as expected), but "grep" is not aware of it until it tries to write the next line (the second match). When it does, it finds out the pipe is closed so it also finishes.
That's normally not a problem, but if you have an infinite input stream containing only one match, it won't never stop. Any solution?
---------- Post updated at 10:51 PM ---------- Previous update was at 10:38 PM ----------
For the example code you used in your original post:
#!/bin/bash
counter() {
seq 1000 | while read NUM; do
echo $NUM
echo "debug: $NUM" >&2
sleep 0.1 # slow it down so we know when this loop really ends
done
}
mkfifo p
counter | grep --line-buffered "[27]" > p &
head -n1 p
kill %?counter
If you make it sleep shorter time or make your machine busier, you will observe your original problem with named pipe (or any other methods). A Unix pipe has at least 4k buffer size and I don't think there is a way to make it smaller. Without a way to reduce the pipe size and not able to modify the streaming code, I see no way to solve your problem.
If you're saying that the loop may run a few more times, sure. You are quite correct. The generator will write a few bytes into the pipe's buffer, never filling the buffer, and will loop until its timeslice is exhausted. But a few extra loop iterations is not the same as his original problem, in which the generator would run without end.