Here's what I could come up with - its a bit messy, but foo
is run in the top-level shell context and its output is provided in the variable a
in the top-level shell context:
#!/bin/bash
foo () { echo ${BASH_SUBSHELL}; }
mkfifo /tmp/fifo{1,2}
{
# block, then read everything in fifo1 into the buffer array
i=0
while IFS='' read -r ln; do
buf[$((i++))]="$ln"
done < /tmp/fifo1
# then write everything in the buffer array to fifo2
for i in ${!buf[@]}; do
printf "%s\n" "${buf[$i]}"
done > /tmp/fifo2
} &
foo > /tmp/fifo1
read a < /tmp/fifo2
echo $a
rm /tmp/fifo{1,2}
This of course assumes two things:
- fifos are allowed
- The command group that is doing the buffering is allowed to be put into the background
I tested this to work in these bash versions:
- 3.00.15(1)-release (x86_64-redhat-linux-gnu)
- 3.2.48(1)-release (x86_64-apple-darwin12)
- 4.2.25(1)-release (x86_64-pc-linux-gnu)
Addendum
I'm not sure the mapfile
approach in bash 4.x does what you want, as the process substitution <()
creates a whole new bash process (though not a bash subshell within that bash process):
$ bar () { echo "$BASH_SUBSHELL $BASHPID"; }
$ bar
0 2636
$ mapfile -t bar_output < <(bar)
$ echo ${bar_output[0]}
0 60780
$
So while $BASH_SUBSHELL
is 0 here, it is because it is at the top level of the new shell process 60780 in the process substitution.