为什么在使用 heredoc 作为 shell 的输入时关闭标准输入

Why is stdin closed when using a heredoc as input to shell

我对此有点困惑

$ bash <<EOF
  read -p 'This will not work' input
EOF

因为

$ cat script
read -p 'This will work fine' input
$ bash script
This will work fine

有什么区别?这似乎是一种标准行为,因为 ash 的行为方式完全相同。


根据目前提供的答案,我怀疑(然后确认)以下方法有效。我认为这实际上是我一直想做的,但是 <() 语法总是我忘记存在的语法。

$ bash <( cat <<EOF
  read -p 'This works' input
EOF
)

每个进程不能同时有多个 stdin,因此作为输入传递给 bash 的此处文档不能包含 read -p.

对于 bash script,运行 script 是 Bash shell 的子进程,并且没有并发的 stdinread,所以它将按预期工作。

在这两种情况下,read 命令从执行它的 bash 进程继承其标准输入。

在第一个示例中,这意味着此处文档实际上包含 read 命令。根据 bash 已经阅读了多少文档(通常是全部),read 没有任何内容可供阅读,因此它以非零退出状态退出。

在第二个示例中,bash 不同的 文件描述符上打开命名文件。 read 仍然从 bash 进程继承其标准输入,但是这次 bash 根本没有读取它,因此 read 命令获取下一个可用行。这里的标准输入是终端,所以 read 阻塞直到用户输入一行。

由于 read 是一个 bash 内置函数,它从 bash 继承标准输入,如上所述。在第一种情况下,bash 有一个 here 文档作为 stdin(或更专业地说,文件描述符 0)并且没有任何内容可供 read 读取。
read 仅从标准输入 (fd0) 读取,而在第二种情况下,bash 打开另一个文件描述符而不是标准输入来从 script 读取脚本,这 NOT 与传递给 read 的标准输入冲突,因此 read 可以按预期工作。

你可以试试这个来测试一下。

$ bash << EOF
ls -l /proc/$$/fd
EOF


$ cat script.sh
ls -l /proc/$$/fd
$ bash script.sh
如果您比较上述示例的输出,差异就会很明显。

最简单的解决方案是将交互式命令写入临时文件,然后获取临时文件:

cat <<'_EOF_' >/tmp/$$.sh
read -p 'This is an interactive command, please enter a string: ' STRING
_EOF_
# Command in temporary file get executed here
source /tmp/$$.sh
echo "STRING= '$STRING'"