>> 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




Reply via email to