I notice the following inconsistency in behavior. Is it indeed a bug?
If you change "&!" to just "&" you'll observe that the "read" is being stopped by a TTOU signal.
This is happening because it's trying to reset the terminal from "cooked" to "raw" mode on the assumption that it's reading from the shell's standard input rather than the piped input. The same thing will happen with the "-s" option.
This probably should be considered a bug. I believe the below is all that's necessary, but would appreciate another eyeball.
diff --git a/Src/builtin.c b/Src/builtin.c
index 669a47092..1568cf44c 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -6483,7 +6483,7 @@ bin_read(char *name, char **args, Options ops, UNUSED(int func))
} else
readfd = izle = 0;
- if (OPT_ISSET(ops,'s') && SHTTY != -1) {
+ if (OPT_ISSET(ops,'s') && SHTTY == readfd) {
struct ttyinfo ti;
gettyinfo(&ti);
saveti = ti;
@@ -6531,7 +6531,7 @@ bin_read(char *name, char **args, Options ops, UNUSED(int func))
delim = (unsigned char) ((delimstr[0] == Meta) ?
delimstr[1] ^ 32 : delimstr[0]);
#endif
- if (SHTTY != -1) {
+ if (SHTTY == readfd) {
struct ttyinfo ti;
gettyinfo(&ti);
if (! resettty) {
@@ -6691,7 +6691,7 @@ bin_read(char *name, char **args, Options ops, UNUSED(int func))
/* dispose of result appropriately, etc. */
if (isem)
while (val > 0 && read(SHTTY, &d, 1) == 1 && d != '\n');
- else {
+ else if (resettty) {
settyinfo(&shttyinfo);
resettty = 0;
}