Configuration Information Machine: x86_64 OS: linux-gnu Compiler: gcc Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64' -DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='x86_64-pc-linux-gnu' -DCONF_VENDOR='pc' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -I. -I../. -I.././include -I.././lib - D_FORTIFY_SOURCE=2 -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wall uname output: Linux adamant 4.0.0-2-amd64 #1 SMP Debian 4.0.8-2 (2015- 07-22) x86_64 GNU/Linux Machine Type: x86_64-pc-linux-gnu
Bash Version: 4.3 Patch Level: 42 Release Status: release Description: Coprocess's output pipe is destroyed when coprocess terminates (possibly before coprocess output has been read) I realize this is by design, essentially, as Bash's coprocs are meant to be "self-cleaning" - but in practice I think this is a bad policy, as variables and file descriptors used by the script are abruptly removed from the environment. Repeat-By: $ coproc head { head -n 10; } [1] 1864 $ ls >&${head[1]} & # "head" gets its 10 lines, writes them to output pipe, and terminates. $ read -r first_line <&${head[0]} [1]- Done coproc head { head -n 10; } $ read -r second_line <&${head[0]} # ${head[@]} is already unset, and pipes closed, so... -bash: ${head[0]}: ambiguous redirect Fix: Perhaps the simplest fix is just don't close the pipes or unset the variable. Leave that up to the caller. Another option might be to use poll() to check if the pipe is empty prior to closing it: poll_fd.events = (POLLHUP | POLLIN); int poll_result = poll(&poll_fd, 1, 0); // Then don't close the file descriptor until // (!(poll_fd.revents & POLLIN) && (poll_fd.revents & POLLHUP)). But this is still problematic: Suppose the shell script is running a loop, processing lines of text from the coproc: $ while read line <&${coproc[0]}; do cmd $line; done Even if the pipe isn't closed until all the data has been read out of it, the loop may (depending on timing) wind up terminating with an "ambiguous redirect" error (or "unbound variable" if "nounset" is in effect), when it should have ended happily with an EOF condition. Users can work around this by duplicating the file descriptor: $ exec {fd_that_wont_vanish_on_me}<&${coproc[0]}- But it kind of negates the benefit of having coproc accept a name for the fd array if you just wind up having to re-bind it anyway. And the command could still fail if it's not run immediately after launching the coproc. Thus, I think coproc shouldn't close its file descriptors or erase its environment variables. ---GEC