`curl의 차이점은 무엇입니까 | sh`와`sh -c“$ (curl)”`?


23

Docker의 쉬운 설치 방법 중 하나는 다음과 같습니다.

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

그러나 도커 예제를 사용하여 다음과 같은 것을 보았습니다.

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

그것들은 기능적으로 동일한 것으로 보이지만, 다른 것을 사용하는 이유가 있습니까? 아니면 단지 선호 / 미적 인 것입니까?

(알 수없는 출처에서 스크립트를 실행할 때는주의해야합니다.)

답변:


39

실질적인 차이가 있습니다.

curl -sSL https://get.docker.com/ | sh시작 curlsh출력 연결 동시에 curl의 입력을 가진 sh. 스크립트를 실행할 수있는 한 curl빨리 다운로드합니다 (대략) sh. 서버는 리소스를 파일이나 버퍼로 다운로드하거나 브라우저에서 볼 때 타이밍에서 불규칙성을 감지하여 보이지 않는 악성 코드를 주입 ​​할 수 있습니다.

에서 sh -c "$(curl -sSL https://get.docker.com/)", curl(가) 엄격하기 전에 실행되는 sh실행됩니다. 리소스 sh가 시작 되기 전에 리소스의 전체 내용이 다운로드되어 셸로 전달됩니다 . 쉘 은 종료 sh되었을 때만 시작 curl되고 자원의 텍스트를 전달합니다. 서버가 sh통화를 감지 할 수 없습니다 . 연결이 종료 된 후에 만 ​​시작됩니다. 스크립트를 파일로 먼저 다운로드하는 것과 비슷합니다.

(이는 도커의 경우에는 관련이 없지만 일반적으로 문제가 될 수 있으며 두 명령의 실제 차이점을 강조합니다.)


2
고마워, 이것은 둘 사이의 가장 중요한 차이점처럼 보입니다.
Sarke

이 주장을 뒷받침하는 자료를 인용 해 주시겠습니까? 서버가 'sh'호출을 감지하는 방법을 알고 싶습니다.
Alfred Armstrong

1
@ AlfredArmstrong 음, 나는 vulnerable to server-side detection문구에 링크를 넣었습니다 . 블로그 게시물을 통해 어떻게 달성하는지 자세히 설명합니다. TL; DR : 스크립트에서 휴면 상태를 유지하고 서버에서 수신 지연을 관찰하십시오.
Jonas Schäfer

1
@JonasWielicki 감사합니다-링크가 명확하지 않았습니다-귀하의 잘못이 아니고 SE의 CSS로 생각합니다. 사람들은 훌륭하게 몰래 들리지 않습니까? :)
Alfred Armstrong

1
이 모든 것이 누군가가 즉시 잡히지 않고 실제로 그 트릭을 시도했는지 궁금하게 만듭니다. 스크립트가 그러한 트릭 없이도 악의적 인 일을 할 수 있기 때문에 중요하지 않을 수 있으며, 전체를 읽지 않는 사람은 취약 할 수 있습니다.
ilkkachu

11

나는 그들이 실질적으로 동일하다고 생각합니다. 그러나 드문 경우가 있습니다.

$(cmd)의 결과로 대체됩니다 cmd. 해당 결과 명령의 길이가에 의해 반환 된 최대 인수 길이 값을 초과하면 결과 getconf ARG_MAX가 잘리고 예기치 않은 결과가 발생할 수 있습니다.

파이프 옵션에는이 제한이 없습니다. curl명령 의 각 출력 라인은 bash파이프에서 도착할 때 실행됩니다 .

그러나 ARG_MAX는 일반적으로 256,000 자 범위입니다. 도커 설치의 경우 두 방법 중 하나를 사용한다고 확신합니다. :-)


흥미 롭기 때문에 차이가 있습니다. 감사합니다
Sarke

1
확실하지 않은 경우 파이프 방법을 사용하십시오. 내 대답에 환경 설정을 지정하지 않았지만 파이프를 통해 얼마나 많은 데이터가 들어오는 지 알 수 없기 때문에 이러한 종류의 파이프 방법을 선호합니다.
Greg Tarsa

2
"결과가 잘립니다"-셸에서 자동으로 잘리지 않는 오류 메시지가 표시됩니다. 테스트 할 때, 심지어 훨씬 아래의 쉘에서 오류가 발생 ARG_MAX합니다 .bash getconf ARG_MAX는 인쇄 할 때 시스템에서 개별 인수를 131072 바이트로 제한 합니다 2097152. 그러나 오류 또는 잘림은 작동하지 않습니다.
hvd

그러나 Bourne 쉘의 오래된 구현 에는 훨씬 낮은 한계가있었습니다. 4.2BSD에서 한도는 10240 자이며, 이전 시스템에서는 한도가 더 낮았습니다. 물론 30 년 전 이었으므로 오늘날에는 그러한 하한을 겪지 않을 것입니다. 올바르게 기억한다면, 초기 쉘 중 일부는 자동으로 잘립니다.
AndyB

단일 인수에 대한 128 kB 제한은 Linux에 관한 것이며 Bash에 관한 것이 아닙니다.
ilkkachu

8

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

  • 두 명령, curl그리고 sh, 각각의 서브 쉘에서, 같은 시간에 시작됩니다

  • STDOUT curl은 STDIN으로 전달됩니다 sh(이것은 파이프 |가 수행하는 것입니다).

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

  • 대체 명령 $()은 먼저 실행 curl됩니다. 즉 , 서브 쉘에서 먼저 실행됩니다.

  • 명령 $()대체는에서 STDOUT으로 대체됩니다.curl

  • sh -c (비 대화식, 비 로그인 셸)에서 STDOUT을 실행합니다. curl


1
실제 차이가 있습니까?
Sarke

@Sarke 네, 이론적으로는 언급했지만 실제로 거의 눈에 띄지 않습니다. (명령 대체를 인용 부호로 두지 않으면 눈에 띄는 효과가 있습니다.)
heemayl

1
@Sarke, 스크립트가 완전히 다운로드되지 않은 경우 반드시 파이핑시이를 알 수있는 것은 아닙니다. 파이프 연결 프로세스는 해당 신호를 무시할 수 있습니다.
Janus Troelsen

@JanusTroelsen 완전히 다운로드되지 않았다는 것은 무슨 뜻입니까? 서버 오류를 제외하고 왜 이런 일이 발생합니까?이 경우 sh로 파이프 할 것이 없습니다.
hasufell

또는 연결 중단 ... 전송이 실패 할 수있는 여러 가지 방법이 있습니다
Janus Troelsen

0

두 가지 (웹 전체의 다른 답변에서 가져온)의 한 가지 차이점은 전체 스크립트를 한 번에 다운로드하지 않으면 알 수없는 시점에서 스크립트를 절반 쯤 중단하고 명령의 의미를 다음과 같이 변경할 수 있다는 것입니다 처형. 따라서 전체 파일을 먼저 다운로드 한 다음 평가하는 것이 좋습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.