我想下载一个配置脚本,通过 读取一些配置参数read
,并执行它:
curl http://example.com/provisioning.sh | sh
问题是,使用参数read
调用脚本中的命令-i
以提供默认值:
read -p "Name: " -i joe name
echo $name
如果我下载脚本,设置+x
权限并运行它,一切都很好。
如果我使用cat provisioning.sh | sh
or运行它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 功能,而是由 . 支持的扩展bash
。Ubuntu 使用dash
,默认情况下具有最小扩展的最小 POSIX 兼容 shell /bin/sh
。这就是为什么它-i
明确拒绝该选项(尽管它确实支持-p
)。
如果您自己使用功能更强大的 shell,您可以尝试以下操作:
bash <(curl http://example.com/provisioning.sh)
它创建一个管道来bash
读取 from 的输出curl
并将其作为脚本文件参数提供。在这种情况下,脚本的标准输入仍然连接到终端,并且read
可以工作(但请注意该行下方的重要警告)。
答案2
另一种更便携的方法是创建另一个文件描述符:
exec 3<>/dev/tty
read -u 3 -p "Gimme some stuff: " stuff
就我而言,我在脚本中进行了快速查找替换,以便这可以工作:
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