<p>Based on docs for <a href="https://docs.docker.com/compose/compose-file/compose-file-v3/#healthcheck" rel="noreferrer">healthcheck</a> both of them are equal with a tiny difference:</p>
<pre class="lang-yml prettyprint-override"><code>healthcheck:
  test: [&quot;CMD&quot;, &quot;curl&quot;, &quot;-f&quot;, &quot;http://localhost&quot;]
healthcheck:
  test: [&quot;CMD-SHELL&quot;, &quot;curl -f http://localhost || exit 1&quot;]
</code></pre>
<p>As you see there is no difference between them. the former form - <code>CMD</code> - just allow you to pass params separately.</p>

CC BY-SA 4.0
2022-06-29T09:24:45.317Z
Why is `exit 1` not necessary in `CMD` version? Or is it not fully equivalent?
Petr Přikryl
CC BY-SA 4.0
2022-06-29T14:58:36.243Z
@PetrPřikryl thanks for comment, it is just an example. I had no intention. But TBH you mentioned a good point. I cannot test it right now. But I will do it and update the answer.
Mohammad Jawad Barati
CC BY-SA 4.0
2023-06-19T15:13:29.320Z
@PetrPřikryl looking at the documentation of docker-compose and interpreting what is written if you use CMD then wrapping `|| exit 1` is performed automatically, while cmd-shell requires you to wrap a command, Dockerfile expects healthcheck to return 0 or 1 (2 is reserved) and curl can return myriad of error codes
Drachenfels
CC BY-SA 4.0
2022-03-07T09:14:52.460Z
2022-03-07T16:27:48.520Z
2022-03-07T16:27:48.520Z
Mohammad Jawad Barati
<p>Docker can either run the command using <code>CMD</code> which is the equivalent of the OS exec syscall directly in the kernel, or it can run using <code>CMD-SHELL</code> which runs a shell to call your command <em>(typically <code>/bin/sh</code>.)</em></p>
<p>A shell provides functionality you are accustomed to from the command line, including:</p>
<ul>
<li>I/O redirection and pipes (<code>&gt;</code>, <code>&gt;&gt;</code>, <code>&lt;</code>, etc)</li>
<li>Command chaining (<code>&amp;&amp;</code> and <code>||</code>)</li>
<li>Variable expansion (<code>$var</code>)</li>
</ul>
<p>However, a shell may also intercept signals, particularly when running as pid 1, which can prevent a graceful shutdown of a container <em>(not much of an issue for a <code>healthcheck</code>).</em></p>
<p>In addition, to run a the shell syntax, your container's image must include a shell, which means that won't work for images based on <code>scratch</code> that do not include a <code>/bin/sh</code>.</p>

CC BY-SA 4.0
2020-05-03T17:58:28.243Z
2023-06-20T22:00:03.980Z
2023-06-20T22:00:03.980Z
BMitch
<p>As per <a href="https://docs.docker.com/engine/reference/builder/#run" rel="nofollow noreferrer">Docker Documentation</a></p>
<blockquote>
<p>RUN has 2 forms:</p>
<ul>
<li><code>RUN &lt;command&gt;</code> (<em>shell</em> form, the command is run in a shell, which by default is <code>/bin/sh -c</code> on Linux or <code>cmd /S /C</code> on Windows)</li>
<li><code>RUN [&quot;executable&quot;, &quot;param1&quot;, &quot;param2&quot;]</code> (<em>exec</em> form)</li>
</ul>
<p>The <code>RUN</code> instruction will execute any commands in a new layer on top of the current image and commit the results. The resulting committed image will be used for the next step in the <code>Dockerfile</code>.</p>
<p>Layering <code>RUN</code> instructions and generating commits conforms to the core concepts of Docker where commits are cheap and containers can be created from any point in an image’s history, much like source control.</p>
<p>The <em>exec</em> form makes it possible to avoid shell string munging, and to <code>RUN</code> commands using a base image that does not contain the specified shell executable.</p>
</blockquote>
<p>And the second form, <code>exec</code> was created for cases when there is not any <code>shell</code> in containers.</p>
<p>There is appropriate issue for healthchecks: <a href="https://github.com/moby/moby/pull/28679" rel="nofollow noreferrer">Use CMD instead of CMD-SHELL for --healthcheck-cmd by vdemeester · Pull Request #28679 · moby/moby</a></p>
<p>Motivation for the issue is clear:
<a href="https://github.com/moby/moby/pull/28679" rel="nofollow noreferrer">Use CMD instead of CMD-SHELL for --healthcheck-cmd by vdemeester · Pull Request #28679 · moby/moby</a></p>
<p>UPD: both the issue and the PR are closed without fix.</p>
<blockquote>
<p>Using <code>CMD-SHELL</code> will not work on any image that do not ship with a<br />
shell (<code>/bin/sh</code>) and/or that do not define a default shell using<br />
<code>SHELL</code> in <code>Dockerfile</code>.</p>
</blockquote>

CC BY-SA 4.0
2020-05-03T18:06:45.210Z
2022-09-12T11:51:43.013Z
2022-09-12T11:51:43.013Z
Yasen
<p>It's not clear to me what are the differences between <code>CMD</code> and <code>CMD-SHELL</code> in Docker Compose <a href="https://docs.docker.com/compose/compose-file/#healthcheck" rel="noreferrer">healthcheck</a>.</p>

<p>What are the benefits of using <code>CMD-SHELL</code> compared to <code>CMD</code>? What are the use cases for <code>CMD</code> and <code>CMD-SHELL</code>?</p>

<docker><docker-compose>
Healthcheck: CMD vs CMD-SHELL
Zulhilmi Zainudin
# Healthcheck: CMD vs CMD-SHELL

(Asked by: username_0 on 2020-05-03)

It's not clear to me what are the differences between `CMD` and `CMD-SHELL` in Docker Compose [healthcheck](https://docs.docker.com/compose/compose-file/#healthcheck).

What are the benefits of using `CMD-SHELL` compared to `CMD`? What are the use cases for `CMD` and `CMD-SHELL`?

**Tags:** docker, docker-compose


---

## 3 answers

### Answer by username_4 on 2020-05-03. Score: 31

Docker can either run the command using `CMD` which is the equivalent of the OS exec syscall directly in the kernel, or it can run using `CMD-SHELL` which runs a shell to call your command *(typically `/bin/sh`.)*

A shell provides functionality you are accustomed to from the command line, including:

* I/O redirection and pipes (`>`, `>>`, `<`, etc)
* Command chaining (`&&` and `||`)
* Variable expansion (`$var`)

However, a shell may also intercept signals, particularly when running as pid 1, which can prevent a graceful shutdown of a container *(not much of an issue for a `healthcheck`).*

In addition, to run a the shell syntax, your container's image must include a shell, which means that won't work for images based on `scratch` that do not include a `/bin/sh`.


---

### Answer by username_5 on 2020-05-03. Score: 8

As per [Docker Documentation](https://docs.docker.com/engine/reference/builder/#run)

> RUN has 2 forms:
>
> * `RUN`  (*shell* form, the command is run in a shell, which by default is `/bin/sh -c` on Linux or `cmd /S /C` on Windows)
> * `RUN ["executable", "param1", "param2"]` (*exec* form)
>
> The `RUN` instruction will execute any commands in a new layer on top of the current image and commit the results. The resulting committed image will be used for the next step in the `Dockerfile`.
>
> Layering `RUN` instructions and generating commits conforms to the core concepts of Docker where commits are cheap and containers can be created from any point in an image’s history, much like source control.
>
> The *exec* form makes it possible to avoid shell string munging, and to `RUN` commands using a base image that does not contain the specified shell executable.

And the second form, `exec` was created for cases when there is not any `shell` in containers.

There is appropriate issue for healthchecks: [Use CMD instead of CMD-SHELL for --healthcheck-cmd by vdemeester · Pull Request #28679 · moby/moby](https://github.com/moby/moby/pull/28679)

Motivation for the issue is clear:
[Use CMD instead of CMD-SHELL for --healthcheck-cmd by vdemeester · Pull Request #28679 · moby/moby](https://github.com/moby/moby/pull/28679)

UPD: both the issue and the PR are closed without fix.

> Using `CMD-SHELL` will not work on any image that do not ship with a  
> shell (`/bin/sh`) and/or that do not define a default shell using  
> `SHELL` in `Dockerfile`.


---

### Answer by username_1 on 2022-03-07. Score: 5

Based on docs for healthcheck both of them are equal with a tiny difference:
healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost"]
healthcheck:
  test: ["CMD-SHELL", "curl -f http://localhost || exit 1"]

As you see there is no difference between them. the former form - CMD - just allow you to pass params separately.

> **Comments:**
> **username_2**: Why is `exit 1` not necessary in `CMD` version? Or is it not fully equivalent?  
> **username_1**: @PetrPřikryl thanks for comment, it is just an example. I had no intention. But TBH you mentioned a good point. I cannot test it right now. But I will do it and update the answer.  
> **username_3**: @PetrPřikryl looking at the documentation of docker-compose and interpreting what is written if you use CMD then wrapping `|| exit 1` is performed automatically, while cmd-shell requires you to wrap a command, Dockerfile expects healthcheck to return 0 or 1 (2 is reserved) and curl can return myriad of error codes  

---

