Qual é a diferença entre 'curl | sh 'e' sh -c “$ (curl)” '?

21

Um método de instalação fácil para o Docker (por exemplo) é o seguinte:

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

No entanto, também vi alguns que se parecem com isso (usando o exemplo do Docker):

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

Eles parecem ser funcionalmente iguais, mas existe um motivo para usar um sobre o outro? Ou é apenas uma coisa de preferência / estética?

(note que tenha muito cuidado ao executar scripts de origens desconhecidas).

    
por Sarke 22.01.2017 / 04:49

3 respostas

33

Existe uma diferença prática.

curl -sSL https://get.docker.com/ | sh inicia curl e sh ao mesmo tempo, conectando a saída de curl com a entrada de sh . curl será executado com o download (aproximadamente) tão rápido quanto sh pode executar o script. O servidor pode detectar as irregularidades no tempo e injetar código malicioso não visível quando simplesmente baixar o recurso em um arquivo ou buffer ou ao visualizá-lo em um navegador.

Em sh -c "$(curl -sSL https://get.docker.com/)" , curl é executado estritamente antes que o sh seja executado. Todo o conteúdo do recurso é baixado e passado para o seu shell antes que o sh seja iniciado. Seu shell só inicia sh quando curl saiu e passa o texto do recurso para ele. O servidor não pode detectar a sh call; só é iniciado depois que a conexão termina. É semelhante ao download do script em um arquivo primeiro.

(Isso pode não ser relevante no caso docker, mas pode ser um problema em geral e destaca uma diferença prática entre os dois comandos.)

    
por 22.01.2017 / 11:01
10

Eu acredito que eles são praticamente idênticos. No entanto, há casos raros em que eles são diferentes.

$(cmd) é substituído pelos resultados de cmd . Se o comprimento desse comando de resultado exceder o valor máximo do comprimento do argumento retornado por getconf ARG_MAX , ele truncará o resultado, o que pode resultar em resultados imprevisíveis.

A opção de pipe não tem essa limitação. Cada linha de saída do comando curl será executada por bash à medida que chega do pipe.

Mas o ARG_MAX geralmente está no intervalo de 256.000 caracteres. Para uma instalação do docker, eu ficaria confiante usando um dos métodos. : -)

    
por 22.01.2017 / 05:06
8

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

  • Os dois comandos, curl e sh , começarão ao mesmo tempo, nas respectivas subpastas

  • O STDOUT de curl será passado como STDIN para sh (isto é o que pipe, | , faz)

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

  • A substituição do comando, $() , será executada primeiro, ou seja, curl será executado primeiro em uma subshell

  • A substituição do comando, $() , será substituída pelo STDOUT de curl

  • sh -c (shell não interativo, não-login) executará o STDOUT de curl

por 22.01.2017 / 05:02