在从管道执行的bash脚本中使用read -p

时间:2014-04-12 17:37:37

标签: bash pipe wget stdin

我提前道歉 - 我并不完全理解我所要求的理念背后的想法,以便理解为什么它不起作用(我不知道我需要学习什么)。我首先在堆栈交换中搜索了答案 - 我发现了一些似乎可能相关的信息,但没有充分解释这些概念,我理解如何构建一个可行的解决方案。我一直在谷歌搜索,但没有找到任何信息,以我理解的方式描述究竟发生了什么。任何可能帮助我了解正在发生的事情的背景概念的方向都将非常感激。

是否可以在从管道执行的bash脚本中获取用户输入?

例如:

wget -q -O - http://myscript.sh | bash

在剧本中:

read -p "Do some action (y/n): " __response
if [[ "$__response" =~ ^[Yy]$ ]]; then
   echo "Performing some action ..."
fi

据我了解,这不起作用,因为读取尝试从stdin读取输入和bash脚本当前正在“通过该管道执行”(我确信有一种更技术更准确的方式来描述什么是发生了,但我不知道如何)。

我找到了推荐使用的解决方案:

read -t 1 __response </dev/tty

然而,这也不起作用。

为了使这项工作能够理解我需要理解的概念,或者解释它为什么不起作用或解决方案,我们将不胜感激。

2 个答案:

答案 0 :(得分:3)

tty解决方案有效。使用此代码对其进行测试,例如:

$ date | { read -p "Echo date? " r </dev/tty ; [ "$r" = "y" ] && cat || echo OK ; }
Echo date? y
Sat Apr 12 10:51:16 PDT 2014
$ date | { read -p "Echo date? " r </dev/tty ; [ "$r" = "y" ] && cat || echo OK ; }
Echo date? n
OK

来自read的提示出现在终端上,read在决定回复日期之前等待回复。

我上面写的内容与以下两个方面的不同之处在于:

read -t 1 __response </dev/tty

首先,选项-t 1read超时一秒。其次,此命令不提供提示。这两者的结合可能意味着,即使read 简要要求输入,您也不知道。

答案 1 :(得分:2)

无法正常运行的主要原因是,如OP有效地指出的

  • 使用的| 将第一条命令的标准输出作为标准输入发送到第二条命令。在这种情况下,第一个命令是

    wget -q -O - http://myscript.sh
    

    它将通过管道将下载的脚本传递到其解释器bash

  • 脚本中的read语句使用相同的标准输入来获取其值。

所以这里是折叠的地方,因为read不在等待您的输入,而是从其自己的脚本中获取输入。示例:

$ cat - <<EOF | bash 
> set -x
> read p
> somecommand
> echo \$p
> EOF
+ read p
+ echo somecommand
somecommand

在此示例中,我使用了一个通过管道传输到bash的here-document。该脚本允许使用set -x进行调试以显示正在发生的事情。如您所见,somecommand从未执行过,而是由read实际读取并存储在变量p中,然后由echo输出(请注意,$已转义以避免在此文档中被替换)。

那么我们如何才能使其正常工作?

首先,切勿通过管道传递到诸如{ba,k,z,c,tc,}sh之类的解释器。尽管感觉很自然,但是它很难看并且应该避免。更好的方法是使用其任何选项:

  

bash -c string:如果存在-c选项,则从字符串中读取命令。如果字符串后面有参数,则将其分配给位置参数,从$0开始。

$ bash -c "$(command you want to pipe)"

这也适用于zshcshtcshkshsh以及其他许多人。