Constructing commands to run in Docker containers
Tags: tutorial, docker
Published: 2023-07-02 20:40:50

## Intro

In this tutorial I will explain multiple ways you can use to define what you want to run in the container when you start the container. You may think it is easy, since you know you can use the `docker run` command on your host and as an argument pass the command that has to run in the container. You also know you can use the `CMD` instruction in the Dockerfile, but this is not the full story, so let's see our options.

**Note:** The tutorial requires [jq](https://jqlang.github.io/jq/) and recent Bash version installed on your machine.


{% embed https://youtu.be/oJQFKr0JDVY %}

If you want to be notified about other videos, you can subscribe to my channel:

<https://www.youtube.com/@akos.takacs>

## Table of contents

- [Important facts](#important-facts)
- [Examples](#examples)
  - [Example 1 - CMD in exec form](#example-1-cmd-in-exec-form)
  - [Example 2 - CMD in shell form as a single argument](#example-2-cmd-in-shell-form-as-a-single-argument)
  - [Example 3 - CMD in shell form as multiple arguments](#example-3-cmd-in-shell-form-as-multiple-arguments)
  - [Example 4 - CMD in shell form running a script without a shebang line](#example-4-cmd-in-shell-form-running-a-shell-script-without-a-shebang-line)
  - [Example 5 - Use anything as shell](#example-5-use-anything-as-shell)
  - [Example 6 - Shell script without shebang line as entrypoint in shell form](#example-6-shell-script-without-shebang-line-as-entrypoint-in-shell-form)
  - [Example 7 - Shell script without shebang line as entrypoint in exec form](#example-7-shell-script-without-shebang-line-as-entrypoint-in-exec-form)
  - [Example 8 - Shell script with shebang line executing the CMD](#example-8-shell-script-with-shebang-line-executing-the-cmd)
  - [Example 9 - Using a fake shell to make a file executable](#example-9-using-a-fake-shell-to-make-a-file-executable)
  - [Example 10 - Failing RUN instruction in exec form](#example-10-failing-run-instruction-in-exec-form)
  - [Example 11 - Working RUN instruction in exec form](#example-11-working-run-instruction-in-exec-form)
- [Conclusion](#conclusion)


## Important facts

[» Back to table of contents «](#table-of-contents)

Before we begin running containers let's learn about the facts this tutorial was built around.

- The actual command running in the container is based on the `SHELL`, `ENTRYPOINT` and the `CMD` instructions in the Dockerfile.
- Commands defined as arguments of the `RUN` instruction will run during the build and never in the container started from the final image.
- The `RUN`, `ENTRYPOINT` and the `CMD` instructions can be written in the `exec form` and the `shell form`.
- The arguments of the `CMD` or instruction will be the arguments of the command defined as
  - an `ENTRYPOINT` if that exists and `CMD` is written in the `exec form`.
  - a `SHELL` if that exists and `CMD` is written in the `shell form`.
- `shell form` means we define the command as a `string` and `exec form` means we define the command as a json list like `["echo", "Hello"]`.
- The `SHELL` instruction must be written in the `exec form` as there is no other shell to which you could pass the command defined as a shell.
- Passing commands as an argument to `docker run` is always equivalent to writing the `CMD` instruction in the `exec form` so the command will always be the argument of the entrypoint and never the shell.
- If you don't have a shell, variables are not evaluated, so `echo $HOME` would just show `$HOME` on the console and the value of the variable.
- Using `docker run` allows you to use variables which will be evaluated outside the container and not inside.
- Even though passing commands to `docker run` is a kind of `exec form`, you can manually defined the shell in that form as an argument of `docker run`.
- The command defined as a `SHELL` doesn't actually have to be a shell. It can be any command.

## Examples

### Example 1 - CMD in exec form

[» Back to table of contents «](#table-of-contents)

We need to create a simple Dockerfile called `Dockerfile.v1` like this:

```Dockerfile
FROM ubuntu:22.04

CMD ["echo", "$HOME"]
```

Let's build the image and run the container.

```bash
docker build . --force-rm -f Dockerfile.v1 -t localhost/command:v1
docker run -i --name "command-v1-0" "localhost/command:v1"
```

And the output is

```text
$HOME
```

We basically told Docker to execute `echo $HOME` without evaluating the variable `$HOME`. If you want to get the same result in your terminal interactively, you have to use apostrophes around each part of the command.

```bash
'echo' '$HOME'
```

Since `echo` is the same without apostrophes, you could just run the following:

```bash
echo '$HOME'
```

So the statement that the `exec form` will not evaluate variables is proven, but the interactive examples doesn't prove that we don't have a shell. Let's ask Docker what command it actually ran.

**Note:** The jq part is required only because the original output would container a quoted string.

```bash
docker container ls -a --no-trunc --format '{{ .Command }}' --filter 'name=^command-v1-0$' \
  | jq --raw-output
```

It shows that the actual command running in the container is

```bash
echo 'My home is $HOME'
```

In some shells like zshell `echo` is a built-in command, but in bash in our container it is at `/usr/bin/echo`. You can check this by running the following using the base image:

```bash
docker run -it --rm ubuntu:22.04 which echo
```

So Docker just ran the binary instead of using a shell. Now let's pass the command as an argument to `docker run`.

```bash
docker run -i --name "command-v1-1" "localhost/rimelek/tutorial-docker-command:v1" \
  echo "My home is $HOME"
```

In this case the output on my machine is

```text
My home is /Users/ta
```

because my home dir on Mac is indeed `/Users/ta` and the variable was interpreted on the host, not in the container. This is the only reason it worked, but it could not use a variable this way inside the container.

And finally, check the command that ran in the container:

```bash
docker container ls -a --no-trunc --format '{{ .Command }}' --filter 'name=^command-v1-1$' \
  | jq --raw-output
```

Output:

```text
echo 'My home is /Users/ta'
```

### Example 2 - CMD in shell form as a single argument

[» Back to table of contents «](#table-of-contents)

Now we will try the `shell form` in a `CMD` instruction. We have actually two ways to do this. First we will quote the entire command as a single argument of the `CMD` instruction. The content of `Dockerfile.v2` is the following:

```Dockerfile
FROM ubuntu:22.04

CMD "echo \"My home is $HOME\""
```

```bash
docker build . --force-rm -f Dockerfile.v2 -t localhost/rimelek/tutorial-docker-command:v2
docker run -i --name "command-v2-0" "localhost/rimelek/tutorial-docker-command:v2"
```

It will show you the folowing error message:

```text
/bin/sh: 1: echo "My home is /root": not found
```

The fact is that the CMD instruction's argument is not just what you quote but it also includes the quote itself. It means that `echo "My home is $HOME"` was interpreted as a single executable filename which couldn't be found obsiously. Let's find out what the command was in the container:

```bash
docker container ls -a --no-trunc --format '{{ .Command }}' --filter 'name=^command-v2-0$' \
  | jq --raw-output
```

Output:

```text
/bin/sh -c '"echo \"My home is $HOME\""'
```

If you try it with an argument passed to `docker run`, as I mentioned at the beginning of the tutorial, we will actually use the `exec form`, so what happens then?

```bash
docker run -i --name "command-v2-1" "localhost/rimelek/tutorial-docker-command:v2" \
  "echo \"My home is $HOME\""
```

We will get an error message, but in this case not from the process inside the container because the exec form will be interpreted by Docker itself:

```text
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "echo \"My home is /Users/ta\"": stat echo "My home is /Users/ta": no such file or directory: unknown.
time="2023-07-02T13:12:52+02:00" level=error msg="error waiting for container: "
```

The environment variable was evaluated, but Docker couldn't find `"echo \"My home is $HOME\""` as a single executable file, so it could not start the container, therefore we don't have any output. You can run

```bash
docker logs command-v2-1
```

to confirm it. In any other case when Docker can start the container the error will be thrown by the the process inside the container wich will generate logs. You could check the running command in the container, but it won't be different from a working command because the original quotation mark will be lost in the output:

```bash
docker container ls -a --no-trunc --format '{{ .Command }}' --filter 'name=^command-v2-1$' \
  | jq --raw-output
```

```text
echo "My home is /Users/ta"
```

### Example 3 - CMD in shell form as multiple arguments

[» Back to table of contents «](#table-of-contents)

Our new Dockerfile will be `Dockerfile.v3`:

```Dockerfile
FROM ubuntu:22.04

CMD echo "My home is $HOME"
```

Now we still use the `CMD` instruction, but in this case we don't quote the value as a single argument.

```bash
docker build . --force-rm -f Dockerfile.v3 -t localhost/rimelek/tutorial-docker-command:v3
docker run -i --name "command-v3-0" "localhost/rimelek/tutorial-docker-command:v3"
```

The output now shows the value of the envrionment variable `$HOME` inside the container:

```text
My home is /root
```

It works, because now we used a correct `shell form`. We check the command inside the container:

```bash
docker container ls -a --no-trunc --format '{{ .Command }}' --filter 'name=^command-v3-0$' \
  | jq --raw-output
```

and the output is:

```text
/bin/sh -c 'echo "My home is $HOME"'
```

It clearly shows that the argument of the `CMD` instruction became the argument of `/bin/sh -c` which is the default value of the `SHELL` instruction in the Dockerfile. Passing the command as an argument of `docker run` would again evaluate the variable on the host:

```bash
docker run -i --name "command-v3-1" "localhost/rimelek/tutorial-docker-command:v3" \
  echo "My home is $HOME"
```

Output:

```text
My home is /Users/ta
```

Check the running command inside the container:

```bash
docker container ls -a --no-trunc --format '{{ .Command }}' --filter 'name=^command-v3-1$' \
  | jq --raw-output
```

Output:

```text
echo 'My home is /Users/ta'
```

### Example 4 - CMD in shell form running a shell script without a shebang line

[» Back to table of contents «](#table-of-contents)

The next example using `Dockerfile.v4` shows how you can use shell scripts with the `CMD` instruction.

```Dockerfile
FROM ubuntu:22.04

COPY src/hello.sh /

# COPY --chmod is supported with buildkit instead of the below instruction
RUN chmod +x /hello.sh

CMD /hello.sh
```

Note that we also use a `RUN` instruction written in the `shell form` which is what we usually do as opposed to how we use the `CMD` instruction in which we usually use the `exec form`, but during the build process we often need a shell to use variables and pipe run a chain of commands. In this example we will stick to the `shell form` in `CMD`, so `hello.sh` will be the argument of the default shell again, which is `/bin/sh -c`.

```bash
docker build . --force-rm -f Dockerfile.v4 -t localhost/rimelek/tutorial-docker-command:v4
docker run -i --name "command-v4-0" "localhost/rimelek/tutorial-docker-command:v4"
```

The output:

```text
Hello Docker
```

Let's check the content of `hello.sh` and how we got this output:

```bash
name="${*:-Docker}"

echo "Hello $name"
```

You probably noticed that there is no shebang line (`#!/bin/bash`) at the beginning of the file. Although many shell script has one, it is not required if you always want to pass the file to a specific shell as argument. And this is what happens using the `shell form`.

Check the command running in the container:

```bash
docker container ls -a --no-trunc --format '{{ .Command }}' --filter 'name=^command-v4-0$' \
  | jq --raw-output
```

Output

```text
/bin/sh -c /hello.sh
```

You know what's coming, we will use the exec form with the Docker CLI:

```bash
docker run -i --name "command-v4-0" "localhost/rimelek/tutorial-docker-command:v4" /hello.sh
```

Remember, in this case there is no shell involved automatically, so the comman will fail:

```text
exec /hello.sh: exec format error
```

Check the running command in the container:

```bash
docker container ls -a --no-trunc --format '{{ .Command }}' --filter 'name=^command-v4-1$' \
  | jq --raw-output
```

The output:

```text
/hello.sh
```

So `hello.sh` was executaed without the shebang line and without any manually provided shell. That will not work. We will get back to this later.

### Example 5 - Use anything as shell

[» Back to table of contents «](#table-of-contents)

The 5th example shows that we can override the default shell and that doesn't even have to be an actuall shell. That perfectly demonstrates that the `SHELL`, `ENTRYPOINT` and `CMD` instructions are all about what will be the argument of what and knowing that you can do whatever you want with this information.

Our `Dockerfile.v5` is the following:

```Dockerfile
FROM ubuntu:22.04

COPY src/hello.sh /

RUN chmod +x /hello.sh

SHELL ["/bin/ls", "-l"]

CMD /hello.sh
```

As funny as it is, we will use the `ls` command in the `SHELL` instruction which will take `hello.sh` as an argument. You can guess that it will just show the file path when we start the container, but let's build the image.

```bash
docker build . --force-rm -f Dockerfile.v5 -t localhost/rimelek/tutorial-docker-command:v5
docker run -i --name "command-v5-0" "localhost/rimelek/tutorial-docker-command:v5"
```

The output is:

```text
-rwxr-xr-x 1 root root 40 Jun 20 18:05 /hello.sh
```

Check what the running command was:

```bash
docker container ls -a --no-trunc --format '{{ .Command }}' --filter 'name=^command-v5-0$' \
  | jq --raw-output
```

Output:

```text
/bin/ls -l /hello.sh
```

So it's time to use the exec form with the Docker CLI:

```bash
docker run -i --name "command-v5-1" "localhost/rimelek/tutorial-docker-command:v5" /hello.sh
```

It fails because the `ls` command was the shell and not the entrypoint.

Here comes the command checking:

```bash
docker container ls -a --no-trunc --format '{{ .Command }}' --filter 'name=^command-v5-1$' \
  | jq --raw-output
```

Output

```text
hello.sh
```

Nothing surprising.

### Example 6 - Shell script without shebang line as entrypoint in shell form

[» Back to table of contents «](#table-of-contents)

Since in the previous example the problem was the entrypoint, let's use one in `Dockerfile.v6`:

```Dockerfile
FROM ubuntu:22.04

COPY src/hello.sh /

RUN chmod +x /hello.sh

SHELL ["/bin/bash", "-c"]

ENTRYPOINT /hello.sh

CMD my friend
```

Build the image and run the container:

```bash
docker build . --force-rm -f Dockerfile.v6 -t localhost/rimelek/tutorial-docker-command:v6
docker run -i --name "command-v6-0" "localhost/rimelek/tutorial-docker-command:v6"
```

The output is:

```text
Hello Docker
```

Shouldn't the `CMD` be the agument of the entrypoint? Why did we get "Hello Docker" instead of "Hello my friend"? Let's check what was running in the container:

```bash
docker container ls -a --no-trunc --format '{{ .Command }}' --filter 'name=^command-v6-0$' \
  | jq --raw-output
```

Output:

```text
/bin/bash -c /hello.sh /bin/bash -c 'my friend'
```

Since we wrote the `ENTRYPOINT` instruction in the `shell form`, it behaved exactly as the `CMD` would have worked. It became the argument of the shell which changed the original entrypoint to the following:

```bash
/bin/bash -c /hello.sh
```

Then we also wrote the `CMD` instruction in `shell form` so the new command became:

```bash
/bin/bash -c 'my friend'
```

It seems because everything is in shell form the modified command could become the argument of the modified entrypoint, but it doesn't make sense, since the bash shell does not take any more arguments when we define the shell script as a command instead of a script file, so everything after `-c hello.sh` will be ignored without throwing any error message. It isn't a big issue, since the `ENTRYPOINT` instruction is usually used in the `exec form`, but what happens if we pass the string "my friend" to `docker run` as an argument.

```bash
docker run -i --name "command-v6-1" "localhost/rimelek/tutorial-docker-command:v6" my friend
```

Output:

```text
Hello Docker
```

Something is still wrong, so let's check the command that was running in the container:

```bash
docker container ls -a --no-trunc --format '{{ .Command }}' --filter 'name=^command-v6-1$' \
  | jq --raw-output
```

Output:

```text
/bin/bash -c /hello.sh my friend
```

"my friend" is still an ignored argument of of the bash shell, since we left the entrypoint in the `shell form`.

### Example 7 - Shell script without shebang line as entrypoint in exec form

[» Back to table of contents «](#table-of-contents)

In this example with the help of `Dockerfile.v7` we will fix the entrypoint and the command to use the `exec form` as recommended.

```Dockerfile
FROM ubuntu:22.04

COPY src/hello.sh /

RUN chmod +x /hello.sh

SHELL ["/bin/bash", "-c"]

ENTRYPOINT ["/hello.sh"]

CMD ["my", "friend"]
```

Let's build the image and start the container:

```bash
docker build . --force-rm -f Dockerfile.v7 -t localhost/rimelek/tutorial-docker-command:v7
docker run -i --name "command-v7-0" "localhost/rimelek/tutorial-docker-command:v7"
```

And now we are back to the previous problem. We still don't have a shebang line in the script, so we get the error message:

```text
exec /hello.sh: exec format error
```

This time `my friend` became the argument of `hello.sh` properly, but `hello.sh` still can't be interpreted because of the lack of the shebang line or any provided shell.

Check the command that resulted the error:

```bash
docker container ls -a --no-trunc --format '{{ .Command }}' --filter 'name=^command-v7-0$' \
  | jq --raw-output
```

Output

```text
/hello.sh my friend
```

Even if we pass "my freind" as an argument of `docker run` it wont change anything, since we already used
the `exec form`.

```bash
docker run -i --name "command-v7-1" "localhost/rimelek/tutorial-docker-command:v7" my friend
```

```text
exec /hello.sh: exec format error
```

```bash
docker container ls -a --no-trunc --format '{{ .Command }}' --filter 'name=^command-v7-1$' \
  | jq --raw-output
```

Output

```text
/hello.sh my friend
```

### Example 8 - Shell script with shebang line executing the CMD

[» Back to table of contents «](#table-of-contents)

We need to use a new script with a shebang line that defines the shell in the first line. The new Dockerfile called `Dockerfile.v8` will make sure the new `hello-bash.sh` will be copied:

```Dockerfile
FROM ubuntu:22.04

COPY src/hello-bash.sh /

RUN chmod +x /hello-bash.sh

SHELL ["/bin/bash", "-c"]

ENTRYPOINT ["/hello-bash.sh"]

CMD ["whoami"]
```

The content of the new shell script is:

```bash
#!/bin/bash

"$@"
```

It will let us define a command as an argument that has to be executaed in the script. Let's run the first container with this script:

```bash
docker build . --force-rm -f Dockerfile.v8 -t localhost/rimelek/tutorial-docker-command:v8
docker run -i --name "command-v8-0" "localhost/rimelek/tutorial-docker-command:v8"
```

The output:

```text
root
```

And check the command that was running on the container:

```bash
docker container ls -a --no-trunc --format '{{ .Command }}' --filter 'name=^command-v8-0$' \
  | jq --raw-output
```

Output:

```text
/hello-bash.sh whoami
```

So even by using the exec form, you can have a shell script if you have a shell defined in the first line.

**Note:** You would probably expect `/bin/bash -c '/hello-bash.sh whoami'` to be the actual running command in the container since I stated that the command worked because there was a shell. Your expectation is almost correct, but we can't get that command from the metadata given us by `docker container ls`. Up until now everything could be determined based on the content of the Dockerfile, but the shebang line is not known directly by Docker and in this case the shell script wasn't passed to the shell defined in the Dockerfile, so the final command will be different.

Let's pass the executable command as an argument of `docker run`:

```bash
docker run -i --name "command-v8-1" "localhost/rimelek/tutorial-docker-command:v8" whoami
```

The output is still just `root` and the final command is still the same too.

```bash
docker container ls -a --no-trunc --format '{{ .Command }}' --filter 'name=^command-v8-1$' \
  | jq --raw-output
```

Output:

```text
/hello-bash.sh whoami
```

If you change the command to be `ps 1` you can get the running process from the container's point of view:

```bash
docker run --rm  "localhost/rimelek/tutorial-docker-command:v8" ps 1
```

Output:

```text
  PID TTY      STAT   TIME COMMAND
    1 ?        Ss     0:00 /bin/bash /hello-bash.sh ps 1
```

And now we have the bash shell and its aguments. It executes `/hello-bash.sh` and since we didn't use the `-c` option to define a command as a string, it won't ignore the rest of the arguments but recognizes the shell script as a file and passes the rest of the arguments to it.

### Example 9 - Using a fake shell to make a file executable

[» Back to table of contents «](#table-of-contents)

At the beginning of this post I mentioned that we can also write the `RUN` instruction in two different forms and we already used it in the shell form. Depending on what the shell is, you might want to write it in the `exec form`, but first let's keep the `shell form` what we usually use. Since we don't really want to run the script during build, we will also change the shell again to `chmod` so instead of running it in a shell we will make it executable this way.

```Dockerfile
FROM ubuntu:22.04

COPY src/hello-bash.sh /

SHELL ["chmod", "+x"]

RUN /hello-bash.sh

SHELL ["/bin/bash", "-c"]

ENTRYPOINT ["/hello-bash.sh"]

CMD ["whoami"]
```

Build and run the container:

```bash
docker build . --force-rm -f Dockerfile.v9 -t localhost/rimelek/tutorial-docker-command:v9
docker run -i --name "command-v9-0" "localhost/rimelek/tutorial-docker-command:v9"
```

The output is

```text
root
```

Note that this example is just preparing ourself to the next one, so it won't give us any interesting output, but since we don't have an error message, we can be sure that the build ran correctly and we could also run a container from it. Let's see the command inside the container.

```bash
docker container ls -a --no-trunc --format '{{ .Command }}' --filter 'name=^command-v9-0$' \
  | jq --raw-output
```

Output:

```text
/hello-bash.sh whoami
```

And now passing whoami as an argument to `docker run`:

```bash
docker run -i --name "command-v9-1" "localhost/rimelek/tutorial-docker-command:v9" whoami
```

The output is still `root` and the running command inside the container didn't change either

```bash
docker container ls -a --no-trunc --format '{{ .Command }}' --filter 'name=^command-v9-1$' \
  | jq --raw-output
```

Output:

```text
/hello-bash.sh whoami
```

### Example 10 - Failing RUN instruction in exec form

[» Back to table of contents «](#table-of-contents)

Now we arrived to the example which will show what happens when you use the `RUN` instruction in the `exec form`. Our Dockefile is `Dockerfile.v10`.

```Dockerfile
FROM ubuntu:22.04

COPY src/hello-bash.sh /

SHELL ["chmod", "+x"]

RUN ["/hello-bash.sh"]

SHELL ["/bin/bash", "-c"]

ENTRYPOINT ["/hello-bash.sh"]

CMD ["whoami"]
```

Build the image

```bash
docker build . --force-rm -f Dockerfile.v10 -t localhost/rimelek/tutorial-docker-command:v10
```

Now it will show an error message, because the `/hello-bash.sh` in the `RUN` instruction wasn't passed to the shell, because it was in the `exec form`. The entrypoint has nothing to do with the `RUN` instruction so we won't end up with an inficnite loop.

The error message is the following:

```text
#7 [3/3] RUN ["/hello-bash.sh"]
#0 0.081 runc run failed: unable to start container process: exec: "/hello-bash.sh": permission denied
#7 ERROR: process "/hello-bash.sh" did not complete successfully: exit code: 1
------
 > [3/3] RUN ["/hello-bash.sh"]:
#0 0.081 runc run failed: unable to start container process: exec: "/hello-bash.sh": permission denied
------
Dockerfile.v10:7
--------------------
   5 |     SHELL ["chmod", "+x"]
   6 |
   7 | >>> RUN ["/hello-bash.sh"]
   8 |
   9 |     SHELL ["/bin/bash", "-c"]
--------------------
ERROR: failed to solve: process "/hello-bash.sh" did not complete successfully: exit code: 1
```

### Example 11 - Working RUN instruction in exec form

[» Back to table of contents «](#table-of-contents)

The last example will show a working version again, but in this case although we still write the `RUN` instruction in the `exec form`, we write it correctly containing the actual `chmod` command instead of relying on the `SHELL`. Let's see the content of `Dockerfile.v11`.

```Dockerfile
FROM ubuntu:22.04

COPY src/hello-bash.sh /

RUN ["chmod", "+x", "/hello-bash.sh"]

SHELL ["/bin/bash", "-c"]

ENTRYPOINT ["/hello-bash.sh"]

CMD ["whoami"]
```

Build and run:

```bash
docker build . --force-rm -f Dockerfile.v11 -t localhost/rimelek/tutorial-docker-command:v11
docker run -i --name "command-v11-0" "localhost/rimelek/tutorial-docker-command:v11"
```

The output is just `root` as in the previously working examples, but this `RUN` instruction wouldn't work if you wanted to use an environment variable in the filename for example, because that would work in a shell only. Without expecting any surprise, let's check the command in the container:

```bash
docker container ls -a --no-trunc --format '{{ .Command }}' --filter 'name=^command-v11-0$' \
  | jq --raw-output
```

Output:

```text
/hello-bash.sh whoami
```

And you would get the same results with the following commands as well:

```bash
docker run -i --name "command-v11-1" "localhost/rimelek/tutorial-docker-command:v11" whoami
```

```bash
docker container ls -a --no-trunc --format '{{ .Command }}' --filter 'name=^command-v11-1$' \
  | jq --raw-output
```

Output:

```text
/hello-bash.sh whoami
```

## Conclusion

[» Back to table of contents «](#table-of-contents)

I hope you now you understand the instructions a little bit better. I used the Docker commands directly so you can copy and paste safely without worrying about what unexpected commands in a script, but you can also clone the Git repository from GitHub and use the scripts mentioned in the readme to have a colored, automatically executed test which you can run as many times as you want and use `./reset.sh` to remove all the generated images and containers.

{% embed https://github.com/rimelek/tutorial-docker-command %}

After cloning the project you might want to switch to `v2.0.0` in case there are newer commits:

```bash
git checkout v2.0.0
```

The output of `./test-all.sh` would be something like this but colored (use the horizontal scrollbar to see the right side of the output):

```text
Container      Command                                          Output
command-v1-0   echo 'My home is $HOME'                          My home is $HOME
command-v1-1   echo 'My home is /Users/ta'                      My home is /Users/ta
command-v2-0   /bin/sh -c '"echo \"My home is $HOME\""'         /bin/sh: 1: echo "My home is /root": not found
command-v2-1   echo "My home is /Users/ta"
command-v3-0   /bin/sh -c 'echo "My home is $HOME"'             My home is /root
command-v3-1   echo 'My home is /Users/ta'                      My home is /Users/ta
command-v4-0   /bin/sh -c /hello.sh                             Hello Docker
command-v4-1   /hello.sh                                        exec /hello.sh: exec format error
command-v5-0   /bin/ls -l /hello.sh                             -rwxr-xr-x 1 root root 40 Jun 20 18:05 /hello.sh
command-v5-1   /hello.sh                                        exec /hello.sh: exec format error
command-v6-0   /bin/bash -c /hello.sh /bin/bash -c 'my friend'  Hello Docker
command-v6-1   /bin/bash -c /hello.sh my friend                 Hello Docker
command-v7-0   /hello.sh my friend                              exec /hello.sh: exec format error
command-v7-1   /hello.sh my friend                              exec /hello.sh: exec format error
command-v8-0   /hello-bash.sh whoami                            root
command-v8-1   /hello-bash.sh whoami                            root
command-v9-0   /hello-bash.sh whoami                            root
command-v9-1   /hello-bash.sh whoami                            root
command-v10-0
command-v10-1
command-v11-0  /hello-bash.sh whoami                            root
command-v11-1  /hello-bash.sh my friend                         Hello my friend
```