`curl | 和有什么不一样?sh` 和`sh -c "$(curl)"`?

Sar*_*rke 30 shell pipe curl command-substitution docker

Docker 的一种简单安装方法(例如)是这样的:

curl -sSL https://get.docker.com/ | sh
Run Code Online (Sandbox Code Playgroud)

但是,我也看到了一些看起来像这样的(使用 Docker 示例):

sh -c "$(curl -sSL https://get.docker.com/)"
Run Code Online (Sandbox Code Playgroud)

它们在功能上似乎相同,但是否有理由使用一个而不是另一个?或者这只是一种偏好/审美?

(请注意,运行来自未知来源的脚本时要非常小心。)

Jon*_*fer 47

有一个实际的区别。

curl -sSL https://get.docker.com/ | sh启动curlsh同时将 的输出curl与 的输入连接shcurl将与sh运行脚本一样快地进行下载(大致)。当简单地将资源下载到文件或缓冲区或在浏览器中查看时,服务器可以检测到时间的不规则并注入不可见的恶意代码。

在 中sh -c "$(curl -sSL https://get.docker.com/)"curl严格在 运行之前sh运行。资源的全部内容在sh启动之前被下载并传递到您的外壳程序。您的 shell 仅shcurl退出时启动,并将资源的文本传递给它。服务器无法检测到sh呼叫;它仅在连接结束后启动。这类似于先将脚本下载到文件中。

(这在 docker 案例中可能不相关,但它可能是一般问题,并突出了两个命令之间的实际差异。)

  • 谢谢,这似乎是两者之间最重要的区别。 (2认同)

Gre*_*rsa 12

我相信它们实际上是相同的。但是,在极少数情况下它们是不同的。

$(cmd)被替换为 的结果cmd。如果该结果命令的长度超过 返回的最大参数长度值getconf ARG_MAX,它将截断结果,这可能会导致不可预测的结果。

管道选项没有这个限制。curl命令的每一行输出将在bash它从管道到达时执行。

但 ARG_MAX 通常在 256,000 个字符范围内。对于 docker 安装,我有信心使用任何一种方法。:-)

  • “它将截断结果”——shell 应该为此发出一条错误消息,而不是静默截断。测试时,我什至从 shell 中收到远低于 `ARG_MAX` 的错误,当 `getconf ARG_MAX` 打印 `2097152` 时,bash 将我系统上的单个参数限制为 131072 字节。但无论哪种方式,错误或截断,它都行不通。 (2认同)

hee*_*ayl 9

curl -sSL https://get.docker.com/ | sh

  • 这两个命令,curl并且sh,将在同一时间开始,在各自的子shell

  • 来自的 STDOUTcurl将作为 STDIN 传递到sh(这就是管道的|作用)

而在sh -c "$(curl -sSL https://get.docker.com/)"

  • 命令替换 ,$()将首先执行,即curl首先在子shell中运行

  • 命令替换 ,$()将被来自的 STDOUT 替换curl

  • sh -c (非交互式、非登录 shell)将从中执行 STDOUT curl