0

I currently try to start background process with coproc and update a name reference variable. My not working code:

function updateVariable(){ local -n myVar="${1}" #i=0; while : do sleep 1 myVar="ok" #((++i)) done } capture=""; coproc mycoproc { updateVariable capture; } 

This does not work as I exspected. echo $capture is just empty. I would exspect it to be "ok".

Thanks a lot!

5
  • 3
    A co-process as its name suggests runs in a different process, so whatever modifications you make to variables in that other process won't affect the variable of the main shell process, you'd need to define a protocol for transmitting that variable (co-processes come two pipes one for input one for output for communication). If you want a variable that is incremented every second, look at the $SECONDS variable. Commented Jul 28, 2020 at 12:56
  • I thought "linking" with a name reference variable could allow me to get a connection to the different process. I know it´s possible to communicate using FDs, but I would need to use echo all the time which means the FD would have many entries than just one single variable. Commented Jul 28, 2020 at 13:17
  • By protocol, I meant you'd need to send something like give-me-a-number to 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. Commented Jul 28, 2020 at 13:31
  • I am not sure if I correctly understand you, but I guess you mean I should perfom some kind of read to always have the latest output saved? My initial idea was using the local -n variable for reading the result back (which under "normal" conditions works just fine). I don´t need to input any number to it. I want to to run always in the background and be able to use the latest result of my background process. Commented Jul 28, 2020 at 13:50
  • 2
    A co-process is a different process, you won't get around that. It's intended to run things like servers that take input from the shell and send output back to it. The only communication channels between the processes are those two file descriptors for input/output, there is no magic sharing of variable values between the processes. That coproc shell process will have its capture variable, 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. Commented Jul 28, 2020 at 14:41

1 Answer 1

1

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.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.