`カール| sh`と`sh -c "$(curl)"`?

`カール| sh`と`sh -c "$(curl)"`?

たとえば、Dockerをインストールする簡単な方法は次のとおりです。

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

ただし、次の内容も見たことがあります(Dockerの例を使用)。

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

機能的には同等のように見えますが、他のものを使用する理由はありますか?それともこれは単に好み/美学ですか?

(不明なソースでスクリプトを実行するときは非常に注意する必要があることは注目に値します。)

答え1

実質的な違いがあります。

curl -sSL https://get.docker.com/ | shの出力をの入力に接続curlし始めます。ダウンロードはおおよそスクリプトの実行速度で行われます。サーバーは次のことができます。shcurlshcurlshタイミングの不規則性を検出リソースを単にファイルやバッファにダウンロードしたり、ブラウザで表示したときに目に見えないマルウェアを挿入します。

では、sh -c "$(curl -sSL https://get.docker.com/)"runの前に厳密に実行してくださいcurl。始める前にshリソースの内容全体がダウンロードされ、シェルに渡されます。shシェルは終了sh時にのみ開始され、curlリソーステキストを渡します。サーバーはsh呼び出しを検出できず、接続が終了した後にのみ開始されます。これは、最初にスクリプトをファイルにダウンロードするのと似ています。

(これはdockerの状況とは関係がないかもしれませんが、一般的に問題になる可能性があり、2つのコマンド間の実際の違いを強調します。)

答え2

私は彼らが実際に同じだと信じています。しかし、まれなケースですが、違います。

$(cmd)結果に置き換えられますcmd。結果コマンドが返された最大引数長の値よりも長い場合、getconf ARG_MAX結果が切り捨てられ、予測不能な結果が発生する可能性があります。

パイプオプションにはこれらの制限はありません。コマンドの各出力行は、パイプから到着すると実行されますcurlbash

ただし、ARG_MAXは通常256,000文字の範囲内です。 Dockerインストールの場合、どちらの方法を使用しても自信があります。 :-)

答え3

存在するcurl -sSL https://get.docker.com/ | sh

  • どちらのコマンドもそのサブシェルで同時に実行されますcurlsh

  • STDOUT fromはcurlSTDINに渡されますsh(これは|パイプ、、の目的です)。

そしてsh -c "$(curl -sSL https://get.docker.com/)"

  • コマンド置換が$()最初に実行されます。つまり、curlサブシェルで最初に実行されます。

  • コマンド置換は$()STDOUT に置き換えられます。curl

  • sh -c(非対話型、非ログインシェル)はSTDOUTを実行します。curl

答え4

(Webの他の回答から得られた)2つの違いの1つは、スクリプト全体を一度にダウンロードしないと、不明な点でスクリプトの半分が切り捨てられ、実行されるコマンドの意味が変更される可能性があることです。 。だから、最初にファイル全体をダウンロードして評価してみるのが良いと思います。

関連情報