【问题标题】:Reading input while also piping a script via stdin读取输入,同时通过标准输入管道传输脚本
【发布时间】:2015-01-18 16:56:51
【问题描述】:

我有一个简单的 Bash 脚本:

#!/usr/bin/env bash
read X
echo "X=$X"

当我使用./myscript.sh 执行它时,它可以工作。但是当我使用cat myscript.sh | bash 执行它时,它实际上将echo "X=$X" 放入$X

所以这个脚本打印出 Hello World 执行 cat myscript.sh | bash:

#!/usr/bin/env bash
read X
hello world
echo "$X"
  • 使用cat myscript.sh | bash 执行脚本有什么好处?为什么不执行与使用 ./myscript.sh 执行相同的操作?
  • 如何避免 Bash 逐行执行,但在 STDIN 到达末尾后执行所有行?

【问题讨论】:

  • 为什么不使用bash ./myscript.sh
  • 或只是./myscript.sh
  • 因为它实际上更复杂。我想编写一个简单的安装程序来下载带有curl 的shell 脚本,然后将其通过管道传输到bash 以避免创建临时文件,就像Composer 使用PHP (getcomposer.org/download) 那样。但是,如果这种方式不起作用,我还需要使用 PHP 或临时文件。
  • @TheFox 然后看看 Ethan 的回答,完全符合“在此设置中您想从哪里读取数据?您可以手动执行此操作(如果您可以定义这样的地方)”。如果有人在看终端,您可以将 read stdin 重定向到 /dev/tty,因为查尔斯刚刚回答了这个问题...
  • @TheFox 了解为什么某人提出问题有助于确定他们提出的问题是否正确。你做什么和你应该做什么有时是两件不同的事情。

标签: bash shell


【解决方案1】:

而不仅仅是运行

read X

...而是将其替换为...

read X </dev/tty || {
  X="some default because we can't read from the TTY here"
}

...如果你想从控制台读取。当然,这仅在您拥有 /dev/tty 时才有效,但如果您想做一些稳健的事情,您不会从curl 管道到外壳。 :)


当然,另一种选择是在命令行中传入 X 的值。

curl https://some.place/with-untrusted-code-only-idiots-will-run-without-reading \
  | bash -s "value of X here"

...当您需要 X 时,请在脚本中引用 "$1"

(顺便说一句,我当然希望您至少为此使用 SSL,而不是建议人们运行他们通过纯 HTTP 下载的代码而无需带外验证步骤。很多人都这样做,当然, 但这会让他们下载的网站——比如rvm.io——成为大目标。大的、易于操作的中间人或 DNS 劫持目标)。

【讨论】:

    【解决方案2】:

    当你 cat 一个脚本来 bash 来执行代码时,来自标准输入

    read 从哪里读取?这也是标准输入。这就是为什么您可以将cat 输入到采用标准输入的程序(如sedawk 等)。

    因此,当您执行此操作时,您本身并没有运行“脚本”。您正在运行一系列输入行。

    您希望read 在此设置中从哪里读取数据?

    您可以手动执行此操作(如果您可以定义这样的位置)。或者,您可以像这样停止运行您的脚本。

    【讨论】:

      最近更新 更多