It looks like the issue is, as suspected, trying to pipe external_program into a detached tee.
In the original script, there was:
printf %s\\n bar | tee foo &
Which doesn't detach tee (only), but the whole pipe sequence in one. So what I originally did was a pipe like this, which gets resolved immediately, i.e. both sleep and noop : get detached together:
$ time sh -c 'sleep 10 | : &'
real 0m0.001s
user 0m0.000s
sys 0m0.001s
Compared toHowever, when detaching tee only inside the function, it was only tee that got detached, not the external program at the beginning of the pipe. Re-using the example with sleep, we can see that only noop : gets detached, but sleep does not, and the script takes the full 10 seconds:
$ time sh -c 'sleep 10 | { : & }'
real 0m10.002s
user 0m0.002s
sys 0m0.000s
The solution is to not detach tee, but the other command:
f() (
mkfifo foo
tr -s '[:lower:]' '[:upper:]' <foo &
tee foo
wait
rm foo
)
printf %s\\n bar | f
Now tee can receive stdout from the pipe, write to the FIFO, and the output of the function is again:
bar
BAR