>> Except that it forks a subshell and consumes trailing newlines, and >> the whole point of this exercise is to avoid forks and spurious >> corruption of trailing newlines. > > I will try to find an alternative to eval $( )
The code below allows the callee to return any kind of values (including arrays). It preserves newlines. This code does not try to hack some half-baked namespaces. The optimized, "coproc" variant does not fork. > Anything repetitive, done often enough, is observable even in an > interactive environment. The bash-completion library of functions does > a _lot_ of repetitive work, and we're talking about some of the core > functions used within that library, possibly even hundreds of times over > the course of a single tab-completion event. Then maybe it's time to consider a non-shell implementation. Could some Bash plugin implement the critical path in C? blackbox1() { local a="some private var" printf "$1=%s;" "foo" printf "$2=%s;" '( some array )' printf "$3=%s;" "'string with embedded new lines '" } blackbox2() { local a="some other private var" printf "$1=%s;" "bar" } # BUG: with bash 4.0.35, repeatedly running this function *too fast* # might error in "Too many open files" forkingMain() { # Sourcing is safe because we trust our own blackbox functions source <(blackbox1 a b c) echo "--- blackbox1 returned:"; declare -p a b c source <(blackbox2 a) echo "--- blackbox2 returned:"; declare -p a } # Re-uses the same coproc subprocess to avoid forking coprocMain() { local returnedDefs echo 'blackbox1 a b c' >&${COPROC[1]} read -r -d $'\0' -u ${COPROC[0]} returnedDefs eval "$returnedDefs" echo "--- blackbox1 returned:"; declare -p a b c echo 'blackbox2 a' >&${COPROC[1]} read -r -d $'\0' -u ${COPROC[0]} returnedDefs eval "$returnedDefs" echo "--- blackbox2 returned:"; declare -p a } forkingMain coproc { while read; do $REPLY; printf '\x00'; done; } coprocMain