One easy install method for Docker (for example) is this:

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

However, I have also seen some that look like this (using the Docker example):

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

They appear to be functionally the same, but is there a reason to use one over the other? Or is it just a preference/aesthetic thing?

(Of note, be very careful when running script from unknown origins.)

share|improve this question

migrated from serverfault.com yesterday

This question came from our site for system and network administrators.

up vote 15 down vote accepted

There is a practical difference.

curl -sSL https://get.docker.com/ | sh is vulnerable to server-side detection and can be used to inject malicious code not visible when simply downloading the resource into a file or buffer or when viewing it in a browser.

In sh -c "$(curl -sSL https://get.docker.com/)", the whole contents of the resource are downloaded first; the server cannot detect the sh call afterwards. It is similar to downloading the script into a file first.

(This may not relevant in the docker case, but it may be a problem in general and highlights a practical difference between the two commands.)

share|improve this answer
1  
Thanks, this seems like the most important difference between the two. – Sarke 21 hours ago

I believe that they are practically identical. However, there are rare cases where they are different.

$(cmd) gets substituted with the results of cmd. Should the length of that result command exceeds the maximum argument length value returned by getconf ARG_MAX, it will truncate the result, which may result in unpredictable results.

The pipe option does not have this limitation. Each line of output from the curl command will be executed by bash as it arrives from the pipe.

But ARG_MAX is usually in the 256,000 character range. For a docker install, I'd be confident using either method. :-)

share|improve this answer
    
Interesting, so there is a difference. Thanks – Sarke yesterday
1  
When in doubt, use the pipe method. I didn't specify a preference in my answer, but I would prefer the pipe method for this kind of use because you never know how much data is coming through the pipe. – Greg Tarsa yesterday
    
"it will truncate the result" -- The shell should issue an error message for that, not silently truncate. When testing, I even get an error from the shell far below ARG_MAX, bash limits an individual argument to 131072 bytes on my system, when getconf ARG_MAX prints 2097152. But either way, error or truncation, it wouldn't work. – hvd 20 hours ago
    
But old implementations of Bourne shell had much lower limits. In 4.2BSD the limit was 10240 characters, and on earlier systems it was even lower.. Of course that was 30 years ago, so you're unlikely to encounter such low limits today. If I recall correctly, some of these early shells did just silently truncate. – AndyB 3 hours ago

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

  • Both commands, curl and sh, will start at the same time, in respective subshells

  • The STDOUT from curl will be passed as the STDIN to sh (this is what pipe, |, does)

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

  • The command substitution, $(), will be executed first i.e. curl will be run first in a subshell

  • The command substitution, $(), will be replaced by the STDOUT from curl

  • sh -c (non-interactive, non-login shell) will execute the STDOUT from curl

share|improve this answer
1  
So, is there any real difference? – Sarke yesterday
    
@Sarke Yes, theoretically like i mentioned, but practically hardly noticeable. (There would be visible effect if you leave the command substitution unquoted.) – heemayl yesterday
1  
@Sarke, if the scripts is not downloaded completely, you wouldn't necessarily notice it with piping. The process getting piped to can ignore that signal. – Janus Troelsen 9 hours ago

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.