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

Fir*_*ire 6 command-line bash scripts pipe

当我卷曲存储在网络服务器上的脚本时,它会无休止地回显我编码的提示,直到我发送 ^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
Run Code Online (Sandbox Code Playgroud)

Raf*_*ffa 6

简单来说

\n

您可能期望read当它\xe2\x80\x99s 在没有管道的情况下运行并等待用户输入\xe2\x80\xa6 时表现相同,那么它不会\xe2\x80\x99t 因为它\xe2\x80\x99s STDIN与匿名管道相关联,唯一通常预期的输入是通过该管道的输入。

\n

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

\n

这很可能是因为通过封闭管道read接收EOF作为其 STDIN,并在每次 while 循环迭代时返回...您可以使用以下命令重现这一点:

\n
echo \'while :; do read -r -p "Y/y" i; echo "${i}$(date)"; done\' | bash\n
Run Code Online (Sandbox Code Playgroud)\n

解决方法是使用bash\ 自己的进程替换语法,<(...)如下所示:

\n
bash <(echo \'while :; do read -r -p "Y/y" i; echo "${i}$(date)"; done\')\n
Run Code Online (Sandbox Code Playgroud)\n

因此,你可以这样做:

\n
bash <(curl https://server/test.sh)\n
Run Code Online (Sandbox Code Playgroud)\n

详细

\n

help read

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

测试和比较EOF退出状态:

\n

Ctrl+终止D将导致EOF):

\n
\nExit Status:\nThe return code is zero, unless end-of-file is encountered, read times out\n(in which case it\'s greater than 128), a variable assignment error occurs,\nor an invalid file descriptor is supplied as the argument to -u.\n
\n

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

\n
$ read input; echo "Exit code for EOF with Ctrl+D is: $?"\nExit code for EOF with Ctrl+D is: 1\n
Run Code Online (Sandbox Code Playgroud)\n

从封闭管道读取:

\n
$ touch emptyfile\n$ read input < emptyfile; echo "Exit code for EOF with reading an empty file is: $?"\nExit code for EOF with reading an empty file is: 1\n
Run Code Online (Sandbox Code Playgroud)\n

在不带管道的情况下隔离bash\ 的退出代码read仅供参考):

\n
$ echo \'read input; echo "Exit code for EOF when reading from a pipe is: $?"\' | bash\nExit code for EOF when reading from a closed pipe is: 1\n
Run Code Online (Sandbox Code Playgroud)\n