为什么Bash read命令在没有任何输入的情况下返回?
我有一个Bash脚本为什么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的
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:感谢您的反馈;我在我的回答中添加了一个更详细的注释作为脚注(作为旁白:你的意思是“makesread
(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