管道“|”后的 bash 内置“read”不会等待用户输入

管道“|”后的 bash 内置“read”不会等待用户输入

当我 curl 存储在我的网络服务器上的脚本时,它会无休止地回显我编写的提示,直到我发送 ^c。我所做的只是一个简单的curl https://server/test.sh | bash。这是通过管道运行的代码

while true
do
        read -r -p "[Y/n] " input

        case $input in
            [yY][eE][sS]|[yY])
                        echo "y"
                        break
                        ;;
            [nN][oO]|[nN])
                        echo "n"
                        break
                        ;;
            *)
                echo "y/n"
                ;;
        esac
done

答案1

简单来说

您可能期望read当它在没有管道的情况下运行并等待用户输入时会以相同的方式行事...但它不会,因为它的 STDIN 与匿名管道绑定,并且唯一通常预期的输入是通过该管道传入的输入。

那么,为什么当不再有输入通过匿名管道并且该管道实际上已经关闭时,它会在循环中立即并反复返回?

这很可能是因为通过封闭的管道read接收作为其 STDIN 并在每次 while 循环迭代时返回...您可以使用例如重现此过程:EOF

echo 'while :; do read -r -p "Y/y" i; echo "${i}$(date)"; done' | bash

一个解决方法是使用bash自己的流程替代语法<(...)如下:

bash <(echo 'while :; do read -r -p "Y/y" i; echo "${i}$(date)"; done')

因此,您可以做这样的事情:

bash <(curl https://server/test.sh)

详细

help read

退出状态:
返回代码为零,除非文件结尾遇到,读取超时
(在这种情况下大于 128),则发生变量赋值错误,
或者向 -u 提供了无效的文件描述符作为参数。

测试并比较EOF退出状态:

Ctrl以+结尾D(将导致EOF):

$ read input; echo "Exit code for EOF with Ctrl+D is: $?"
Exit code for EOF with Ctrl+D is: 1

正在读取空文件(将导致EOF):

$ touch emptyfile
$ read input < emptyfile; echo "Exit code for EOF with reading an empty file is: $?"
Exit code for EOF with reading an empty file is: 1

从封闭的管道读取:

$ echo 'read input; echo "Exit code for EOF when reading from a pipe is: $?"' | bash
Exit code for EOF when reading from a closed pipe is: 1

在没有( 的bash管道之后隔离的退出代码read以供参考):

$ echo 'echo "Exit code for bash alone after a pipe: $?"' | bash
Exit code for bash alone after a pipe: 0

相关内容