我有一个简单的 Bash 脚本:
#!/usr/bin/env bash
read X
echo "X=$X"
当我用./myscript.sh
执行它时,它可以工作。但是当我用cat myscript.sh | bash
执行它时,它实际上echo "X=$X"
$X
.
所以这个脚本打印了用cat myscript.sh | bash
执行的 Hello World:
#!/usr/bin/env bash
read X
hello world
echo "$X"
- 使用
cat myscript.sh | bash
执行脚本有什么好处?为什么不做与我用./myscript.sh
执行它相同的事情? - 如何避免 Bash 逐行执行,而是在 STDIN 到达末尾后执行所有行?
而不是只是运行
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"
。并在需要时参考脚本中的"$1"
X
。
(顺便说一下,我当然希望你至少为此使用SSL,而不是建议人们运行他们通过纯HTTP下载的代码,没有带外验证步骤。当然,很多人都这样做,但这会使他们下载的网站 - 比如rvm.io
- 成为大目标。大型、易于在中间人或 DNS 劫持的目标)。
当您cat
脚本来抨击要执行的代码时,来自标准输入。
read
从哪里阅读?没错,这也是标准输入。这就是为什么你可以cat
输入到接受标准输入的程序(如sed
、awk
等)。
因此,当您执行此操作时,您本身并没有运行"脚本"。您正在运行一系列输入行。
您希望read
在此设置中从何处读取数据?
您可以手动执行此操作(如果可以定义这样的位置)。或者,您可以像这样停止运行脚本。