web-dev-qa-db-ja.com

`curlの違いは何ですか? sh`と `sh -c" $(curl) "`?

Docker(たとえば)の簡単なインストール方法の1つは次のとおりです。

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

ただし、次のようなものも見ました(Dockerの例を使用)。

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

機能的には同じように見えますが、どちらを使用するのですか?それとも単に好み/美的ですか?

(注意してください、出所が不明なスクリプトを実行するときは十分注意してください。)

25
Sarke

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

_curl -sSL https://get.docker.com/ | sh_は、curlshを同時に開始し、curlの出力とshの入力を接続します。 curlshがスクリプトを実行できるのと同じ速さでダウンロードを実行します。サーバーは タイミングの不規則性を検出 でき、リソースをファイルまたはバッファーに単にダウンロードするとき、またはブラウザーで表示するときに、見えない悪意のあるコードを挿入できます。

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

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

42
Jonas Schäfer

私はそれらが実質的に同一であると信じています。ただし、まれに異なる場合があります。

$(cmd)cmdの結果に置き換えられます。その結果コマンドの長さがgetconf ARG_MAXによって返される引数の最大長値を超えると、結果が切り捨てられ、予期しない結果になる可能性があります。

Pipeオプションにはこの制限はありません。 curlコマンドからの出力の各行は、パイプから到達するときにbashによって実行されます。

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

12
Greg Tarsa

_curl -sSL https://get.docker.com/ | sh_内:

  • 両方のコマンドcurlshは、それぞれのサブシェルで同時に開始されます

  • curlからのSTDOUTは、STDINとしてshに渡されます(これは、パイプ__|_が行うことです)

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

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

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

  • _sh -c_(非インタラクティブ、非ログインシェル)はcurlからSTDOUTを実行します

9
heemayl

パイプバージョンでは、curl stdoutをsh stdinにパイプすると、スクリプトの対話性が失われます。そのため、入力を待つときにキーボード入力やスクリプトがクラッシュすることはありません。

ここでの他の答えも重要です。

1
Ondrej Galbavý

2つの違い(Web上の他の回答から取得)の1つは、スクリプト全体を一度にダウンロードしない場合、不明なポイントでスクリプトの途中で切断され、コマンドの意味が次のようになることです。実行されました。したがって、最初にファイル全体をダウンロードしてから、それを評価する方が良いようです。

0
Lance Pollard