Bash 使用 cat 和管道读取命令

Tib*_*ács 2 bash stdin pipe

我有两个脚本:

install.sh

#!/usr/bin/env bash

./internal_install.sh
Run Code Online (Sandbox Code Playgroud)

internal_install.sh

#!/usr/bin/env bash
set -x
while true; do
    read -p "Hello, what's your name? " name
    echo $name
done
Run Code Online (Sandbox Code Playgroud)

当我运行时./install.sh,一切都按预期进行:

> ./install.sh 
+ true
+ read -p 'Hello, what'\''s your name? ' name
Hello, what's your name? Martin
+ echo Martin
Martin
...
Run Code Online (Sandbox Code Playgroud)

但是,当我运行时cat ./install.sh | bash,该read函数不会阻塞:

cat ./install.sh | bash
+ true
+ read -p 'Hello, what'\''s your name? ' name
+ echo

+ true
+ read -p 'Hello, what'\''s your name? ' name
+ echo

...
Run Code Online (Sandbox Code Playgroud)

这只是使用的简化版本,curl会导致相同的问题:

> ./install.sh 
+ true
+ read -p 'Hello, what'\''s your name? ' name
Hello, what's your name? Martin
+ echo Martin
Martin
...
Run Code Online (Sandbox Code Playgroud)

如何使用curl/在内部脚本中cat进行阻塞?read

Bar*_*mar 6

read默认从标准输入读取。当您使用管道时,标准输入是管道,而不是终端。

如果您想始终从终端读取,请将输入重定向read/dev/tty.

#!/usr/bin/env bash
set -x
while true; do
    read -p "Hello, what's your name? " name </dev/tty
    echo $name
done
Run Code Online (Sandbox Code Playgroud)

bash但是您可以通过将脚本作为参数而不是管道来解决问题。

bash ./install.sh
Run Code Online (Sandbox Code Playgroud)

使用curl获取脚本时,可以使用进程替换:

bash <(curl -sl https://www.conteso.com/install.sh)
Run Code Online (Sandbox Code Playgroud)