Configuration Information [Automatically generated, do not change]:
Machine: x86_64
OS: linux-gnu
Compiler: gcc
Compilation CFLAGS: -march=x86-64 -mtune=generic -O2 -pipe -fno-plt
-DDEFAULT_PATH_VALUE='/usr/local/sbin:/usr/local/bin:/usr/bin'
-DSTANDARD_UTILS_PATH='/usr/bin' -DSYS_BASHRC='/etc/bash.bashrc'
-DSYS_BASH_LOGOUT='/etc/bash.bash_logout' -DNON_INTERACTIVE_LOGIN_SHELLS
-Wno-parentheses -Wno-format-security
uname output: Linux leonidas 5.2.11-arch1-1-ARCH #1 SMP PREEMPT Thu Aug
29 08:09:36 UTC 2019 x86_64 GNU/Linux
Machine Type: x86_64-pc-linux-gnu
Bash Version: 5.0
Patch Level: 9
Release Status: release
Description:
I have the following script to synchronize execution of a command
substitution using flock:
touch /tmp/1
echo |
(
flock 13
tee >(
cat
flock -u 13
) >/dev/null
(
flock 13
) 13</tmp/1
) 13</tmp/1
The purpose of the code is to synchronize the output of the command
redirection run "inside" `tee` with the rest of the script. For that,
the "main process" blocks on flock until the command inside redirection
is finished when it unlocks the flock.
However on bash 5.0 The `cat` inside `tee` gets blocked on `read()`.
I have created the following oneliner as an reproducible example:
timeout 1 bash -x -c 'touch /tmp/1; echo | ( flock 13; tee
>(cat; echo "all ok"; flock -u 13) >/dev/null; ( flock 13 ) 13</tmp/1)
13</tmp/1' || echo "not ok"
If I execute it on on any bash<=4 I get `all ok` printed out.
However when run under mine kernel 5.2.11, coreutils 8.31, bash
version 5.0.9(1) on my updated archilinux, the `cat` inside `tee >(cat
...)` gets stuck. The `echo "all ok"` is never executed. The `timeout 1`
fires and `not ok` is printed out. I have also tried `docker run
bash:5.0` and various servers I can access - `not ok` is printed out on
bash v5.
I can also replicate the behavior on `docker run bash:5.0`
The issue was first reported by @LEo on stackoverflow thread:
https://stackoverflow.com/questions/57813225/how-to-assign-output-of-multiple-shell-commmands-to-variable-when-using-tee/57813297?noredirect=1#comment102083293_57813297
I tried inspecting both `tee` and `cat` under `strace`. Well,
`tee` does `close(3)` , where 3 is it's file descriptor to command
redirection. And `cat` just blocks on `read()` call. The empty line from
`echo |` is printed out by `cat`, you can put something in there, for
sure it reads from proper stream. bash<4 closed the stream properly,
bash5.0 seems like doesn't do that and the stream is still open and
`cat` blocks on `read()` call.
Repeat-By:
Simply execute:
timeout 1 bash -x -c 'touch /tmp/1; echo | ( flock 13; tee
>(cat; echo "all ok"; flock -u 13) >/dev/null; ( flock 13 ) 13</tmp/1)
13</tmp/1' || echo "not ok"
If `not ok` is printed out, that means that the bug exists. If
`all ok` is printed out, that means all is ok.