为什么Bash read命令在没有任何输入的情况下返回?

为什么Bash read命令在没有任何输入的情况下返回?,bash,unix,stdin,Bash,Unix,Stdin,我有一个Bash脚本foo,它接受STDIN上的单词列表。脚本应将单词读入数组,然后请求用户输入: while IFS= read -r; do words+=( "$REPLY" ) done read -r ans -p "Do stuff? [Yn] " echo "ans: |$ans|" 问题是,Bash immediate将空字符串读入ans变量,而不等待实际的用户输入。也就是说,我得到以下输出(没有提示或延迟): 既然第一个read调用已经消耗掉了通过管道传输到STDIN的

我有一个Bash脚本
foo
,它接受STDIN上的单词列表。脚本应将单词读入数组,然后请求用户输入:

while IFS= read -r; do
  words+=( "$REPLY" )
done

read -r ans -p "Do stuff? [Yn] "
echo "ans: |$ans|"
问题是,Bash immediate将空字符串读入
ans
变量,而不等待实际的用户输入。也就是说,我得到以下输出(没有提示或延迟):


既然第一个
read
调用已经消耗掉了通过管道传输到STDIN的所有内容,为什么第二个
read
调用返回时没有实际读取任何内容?

从您的症状判断,看起来您已重定向stdin以通过输入文件(
foo
)或管道(
…|foo
)向
循环提供单词列表

如果是这样,您的第二个
读取
命令将不会自动切换回从终端读取
;它仍然在读取重定向到的任何stdin,并且如果该输入已被使用(正如注释中指出的,这正是
while
循环所做的),
read
不读取任何内容,并返回退出代码
1
(这就是终止
while
循环的原因)

如果明确希望第二个
read
命令从终端获取用户输入,请使用:

read -r -p "Do stuff? [Yn] " ans </dev/tty

read-r-p“Do stuff?[Yn]”返回而不读取任何内容是您的
while
循环如何首先终止:
read
在没有(完整)行可读取时具有非零退出状态。由于第一次
read
调用已经消耗了通过管道传输到STDIN的所有内容,第二次
read
调用read时已无剩余@Williampersell-我的意思是,这种情况与对终端的
read
调用(无输入重定向)有什么区别?在一个终端
read
调用中,也没有什么可读的,直到我键入一些内容并按enter键。那么,为什么
读取
等待我对该调用的输入而不是在这里?@mklement0感谢您指出这一点!是,^d不关闭stdin^d导致tty刷新其输入缓冲区,该缓冲区(如果为空)导致
read
(系统调用)返回0,而
read
(bash内置)返回0。@williampersell:感谢您的反馈;我在我的回答中添加了一个更详细的注释作为脚注(作为旁白:你的意思是“makes
read
(bash内置)return[set exit code to]1”,而不是0)。很好。我想知道
read
的返回值在
终止时会是多少。我已经得到答案了。:)这种循环的逻辑似乎很好,从可读性的角度来看,它们真的很糟糕。发动机罩后面发生了什么还不清楚。正如Chet Ramey所说,Bourne shell中有一些暗角,人们都使用它们。@sjsam:这些暗角之一是
read
返回退出代码
1
,对于一个没有以换行符(
\n
)结尾的行,尽管读取了值。因此,如果文件的最后一行没有换行符终止,则
while
循环将不会捕获该文件的最后一行。解决方法:
whileread-r行| |[[-n$line];执行…
谢谢@mklement0!请注意,我在原来的问题中删除了read命令中的
$word
打字错误,因为它会分散对真实问题的注意力。作为参考,原始代码为:
,而IFS=read-r字;做单词+=(“$REPLY”);完成
;正如您所指出的,在本例中,该值将存储在
$word
中,而不是
$REPLY
中。要澄清的是,当您说“
read
reads nothing”时,这是否意味着它看到了EOF字符?否则,它怎么知道不会有更多的输入呢?@mklement0:的确如此。你是我翅膀下的风。
read -r -p "Do stuff? [Yn] " ans </dev/tty