Here's an example to update an external named reference via COPROC function, which executes a command from a simple string, var or named reference.
The function coproc_set_var accepts a named reference to update as arg1 and the command as arg2:
#! /bin/sh coproc_set_var() { # Create ref for var to set local -n _var="$1" coproc { local -i isRef isArray local -n _cmd="$2" 2>/dev/null [[ $? -eq 0 ]] && isRef=1 [[ ${_cmd@A} == 'declare -a'* ]] && isArray=1 # Execute COMMAND from ARRAY or REF if [[ $isArray || $isRef ]]; then # ARRAY VAR REF if [[ $isArray ]]; then "${_cmd[@]}" # SIMPLE VAR REF else ${_cmd} fi # Execute COMMAND from STR else #echo -e "CMD_STR: $2" >/dev/tty $2 fi # COMMAND may finish very quickly - check if async main process proceeds, while COPROC runs sleep 1 } read -r _var <&"$COPROC" # Close COPROC (required?) exec {COPROC[1]}>&- } # Set test var with start value tmp='TEST' ## SIMPLE COMMAND VAR / REF cmd='echo COP_INPUT' declare -n cRef=cmd coproc_set_var tmp cmd #coproc_set_var tmp cRef ## SIMPLE COMMAND ARRAY / REF cmdArr=(echo COP_INPUT) declare -n cArrRef=cmdArr #coproc_set_var tmp cmdArr #coproc_set_var tmp cArrRef ## SIMPLE COMMAND VAR / ARRAY STRING #coproc_set_var tmp 'echo COP_INPUT' #coproc_set_var tmp "$cmd" #coproc_set_var tmp "${cmd[@]}" echo -e "DO STUFF" # Ensure COPROC finished all work wait $COPROC_PID # Output updated var echo -e "TMP: $tmp"
Most of the code is inside the anonymous coproc, which uses the function args 1 and 2 and converts them into named references as required.
It also checks for simple and array var references, as well as named references from other references, for a given command, expands and executes it accordingly.
To test the different cases of input commands, uncomment the corresponding test command lines in the lower section.
While the COPROC is invoked and still running, the 'DO STUFF' code after the coproc's invocation is executed and sleep 1 from within the co-process demonstrates it still keeps on working.
It's important, to call wait $COPROC_PID after the asynchronously running 'DO STUFF' code and before the update var is finally accessed, to ensure the coproc's code has finished and the value is updated.
NOTE: such an approach is most likely only useful for very time-consuming, blocking program invocations and in the anonymous form (and up to ~5.x of Bash), only 1 co-process is possible.
Also keep in mind, that from vars, only simple commands can be injected, nothing involving decision logic and special chars.
It should be possible, though, to put such code in separate functions (the best practise) and use those as command args for coproc_set_var.
UPDATE: After doing some tests, it turned out to be a Pyrrhic victory; when executing some more complex/time-consuming commands instead of echo -e "DO STUFF", it's not running asynchronously anymore. At the moment, I've no solution for this.
$SECONDSvariable.echoall the time which means the FD would have many entries than just one single variable.give-me-a-numberto your coproc and read the result back. Shell coprocs are not a very useful feature in general, see How do you use the command coproc in various shells? about that.capturevariable, your main shell process will have its own with no relation between the two other than the coproc's one will have initially been copied from the main shell upon forking.