为什么 sh 运行 read 命令时不采用交互选项?

为什么 sh 运行 read 命令时不采用交互选项?

我想下载一个配置脚本,通过 读取一些配置参数read,并执行它:

curl http://example.com/provisioning.sh | sh

问题是,使用参数read调用脚本中的命令-i以提供默认值:

read -p "Name: " -i joe name
echo $name

如果我下载脚本,设置+x权限并运行它,一切都很好。

如果我使用cat provisioning.sh | shor运行它sh provisioning.sh,它会失败并显示:

read: Illegal option -i

如果通过 sh 运行,为什么不读取提供默认值的支持?

但无论如何,我会删除-i,留下

read -p "Name: " name
echo $name

现在,如果我通过运行脚本cat provisioning.sh | sh,它不会执行任何操作。这是为什么?

Ubuntu 14.04。

答案1

当您将 的输出通过管道传输curl到时sh,您正在使脚本文本成为 shell 的标准输入,shell 将其作为要运行的命令接收。在那之后,就没有什么可留的了read。即使它尝试,它也不会从终端输入中得到任何东西,因为它没有连接到终端输入。管道已取代sh过程的标准输入。

下一个问题read -i不是POSIX sh 功能,而是由 . 支持的扩展bashUbuntu 使用dash,默认情况下具有最小扩展的最小 POSIX 兼容 shell /bin/sh。这就是为什么它-i明确拒绝该选项(尽管它确实支持-p)。

如果您自己使用功能更强大的 shell,您可以尝试以下操作:

bash <(curl http://example.com/provisioning.sh)

它创建一个管道来bash读取 from 的输出curl并将其作为脚本文件参数提供。在这种情况下,脚本的标准输入仍然连接到终端,并且read可以工作(但请注意该行下方的重要警告)。


我还要注意的是curl | sh“ 是一般来说 皱眉头 之上作为一个明显的安全问题,但您最了解脚本所处的情况。

答案2

另一种更便携的方法是创建另一个文件描述符:

exec 3<>/dev/tty
read -u 3 -p "Gimme some stuff: " stuff

我在这里发现: https://superuser.com/questions/834502/possible-to-get-a-bash-script-to-accept-input-from-terminal-if-its-stdin-has-bee

就我而言,我在脚本中进行了快速查找替换,以便这可以工作:

exec 3<>/dev/tty
read_cmd="read -u 3"

$read_cmd -p "name: " my_name
$read_cmd -p "email: " my_email
$read_cmd -s -p "password: " my_password

相关内容