7

The intent of the test script1 below is to start an "outer" coprocess (running seq 3), read from this coprocess in a while-loop, and for each line read, print a line identifying the current iteration of the outer loop, start an "inner" coprocess (also running seq, with new arguments), read from this inner coprocess in a nested while loop, and then clean up this inner coprocess. The nested while loop prints some output for each line it reads from the inner coprocess.

#!/bin/bash
# filename: coproctest.sh
PATH=/bin:/usr/bin

coproc OUTER { seq 3; }
SAVED_OUTER_PID="${OUTER_PID}"

exec {OUTER_READER}<&"${OUTER[0]}"
while IFS= read -r -u "${OUTER_READER}" OUTER_INDEX; do

    printf -- '%d\n' "${OUTER_INDEX}"

    START=$(( OUTER_INDEX * 1000000 ))
    FINISH=$(( START + OUTER_INDEX ))

    # (
      coproc INNER { seq "${START}" "${FINISH}"; }
      SAVED_INNER_PID="${INNER_PID}"
      exec {INNER_READER}<&"{INNER[0]}"

      while IFS= read -r -u "${INNER_READER}" INNER_INDEX; do
          printf -- '    %d\n' "${INNER_INDEX}"
      done

      exec {INNER_READER}<&-

      wait "${SAVED_INNER_PID}"
    # )

done
exec {OUTER_READER}<&-
wait "${SAVED_OUTER_PID}"

When I run this script, this is the output I get:

% ./coproctest.sh
1
./coproctest.sh: line 30: warning: execute_coproc: coproc [12523:OUTER] still exists
./coproctest.sh: line 19: INNER_READER: ambiguous redirect
./coproctest.sh: line 21: read: : invalid file descriptor specification
./coproctest.sh: line 25: INNER_READER: ambiguous redirect
2
./coproctest.sh: line 19: INNER_READER: ambiguous redirect
./coproctest.sh: line 21: read: : invalid file descriptor specification
./coproctest.sh: line 25: INNER_READER: ambiguous redirect
3
./coproctest.sh: line 19: INNER_READER: ambiguous redirect
./coproctest.sh: line 21: read: : invalid file descriptor specification
./coproctest.sh: line 25: INNER_READER: ambiguous redirect

I get pretty much the same output if I uncomment the two commented lines.


Q1: Is it possible to have multiple coprocesses running at the same time?

Q2: If so, how should the script above be modified to achieve the desired output?


1 I've only recently started to work with coprocesses, and there is still a lot I don't understand. As a result, this script almost certainly contains incorrect, awkward, or unnecessary code. Please feel free to comment on and/or fix these weaknesses in your responses.

2 Answers 2

9

From the "BUGS" section at the very end of the bash manual:

There may be only one active coprocess at a time.

3
  • It might be good to state which version you are referring to... Not sure this is still valid now ... the quoted bug is no longer in the manual and bash 4.4 changes report the following which very much suggests multiple coprocs are fine: h. The "name" argument to the "coproc" reserved word now undergoes word expansion, so unique coprocs can be created in loops. (from here) Commented Aug 22, 2024 at 6:22
  • 1
    @raphael I know there is development to allow for multiple co-processes, but the quoted line is still part of the current bash manual (even in the current bleeding-edge development version). I'm assuming the line will be removed from the BUGS section as soon as the feature has been proven to work reliably. As LL3 says in their answer, it may work but you will get no guarantees. Commented Aug 22, 2024 at 6:32
  • thanks for the response! You are of course right... I looked for the line in the "reference manual"... not in the "man page" (accessible via man bash) Commented Aug 22, 2024 at 8:28
2

Q1: Is it possible to have multiple coprocesses running at the same time?

On Bash v4 and above (including current v5), officially no, as noted by @Kusalananda.

However, I can tell you that it might work despite the warning, but of course no guarantee and YMMV. See here for a bit more insight.

Q2: If so, how should the script above be modified to achieve the desired output?

It might (as per above) work just fine once you fix the:

exec {INNER_READER}<&"{INNER[0]}"  # <-- lacks the '$' sign for the 'INNER[0]' variable

which causes the:

./coproctest.sh: line 19: INNER_READER: ambiguous redirect

message, and consequently also the:

./coproctest.sh: line 21: read: : invalid file descriptor specification

message.

It works for me, once fixed that and warning aside.

As for other notes:

  • There's no need to duplicate a coproc's file-descriptors, unless you want to pass them to a child process (a sub-shell or a command or script)
  • You probably did so because the seq command naturally finished quickly, and thus the automatic variables disappeared before you could use them. By doing the way you did, those duplicate file-descriptors will be inherited by all subsequent commands and background processes, which might be undesirable if your co-process actually uses its input pipe and waits for it to be closed in order to exit. So another approach to address that is by a synchronization mechanism, like for instance make your OUTER co-process be { seq 3; exec >&-; read; }, and then when you've consumed its input from the main script do e.g. echo >&${OUTER[1]}; wait "${OUTER_PID}" to let the co-process's read proceed then wait for it. Note that it is not guaranteed that the wait will execute before the $OUTER_PID variable disappears: in such case you can just mute the warning message (or ignore it altogether) and perhaps force a success status with an || true
  • As a personal side-note I can tell you that, if you are really determined in having multiple co-processes simultaneously, you might re-implement a rough equivalent of coproc using Bash v3 syntax over background processes plus mkfifo named-FIFOs, and on Linux also with a trick with Process Substitutions instead of mkfifos. With Bash v4 syntax it can be less complicated, but still a challenging exercise.

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.