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:
$ time sh -c 'sleep 10 | : &'
real 0m0.001s
user 0m0.000s
sys 0m0.001s
Compared to when detaching tee only inside the function:
$ 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
rm foo
)
printf %s\\n bar | f
Now the output is again:
bar
BAR