128

On a Jenkins machine I would like to create a docker container with a specified name only if it does not already exist (in a shell script). I thought I might run the command to create the container regardless and ignore the failure if there was one, but this causes my jenkins job to fail.

Hence, I would like to know how I can check if a docker container exists or not using bash.

anubhava
  • 761,203
  • 64
  • 569
  • 643
kshah
  • 1,667
  • 2
  • 16
  • 24

14 Answers14

222

You can check for non-existence of a running container by grepping for a <name> and fire it up later on like this:

[ ! "$(docker ps -a | grep <name>)" ] && docker run -d --name <name> <image>

Better:

Make use of https://docs.docker.com/engine/reference/commandline/ps/ and check if an exited container blocks, so you can remove it first prior to run the container:

if [ ! "$(docker ps -a -q -f name=<name>)" ]; then
    if [ "$(docker ps -aq -f status=exited -f name=<name>)" ]; then
        # cleanup
        docker rm <name>
    fi
    # run your container
    docker run -d --name <name> my-docker-image
fi
MikeSchinkel
  • 4,947
  • 4
  • 38
  • 46
ferdy
  • 7,366
  • 3
  • 35
  • 46
  • 4
    Right - you need the `-a` or trying to run an exited container will fail. – ldg Jul 26 '16 at 02:03
  • 14
    This response does not work if you have two container with similar name. For example: cool.project (container 1) and dashboard.cool.project (container 2) – Maxim Tkach Mar 13 '17 at 15:22
  • 2
    @MaximTkach That's why using the second approach is better, where you fully qualify the name of the container in the docker ps commands. But you can also introduce a regex in the grep command to look for whitespace before and after the name. This test is intentionally left to the reader. – ferdy Mar 22 '17 at 08:28
  • 1
    syntax error, should be: [ ! "$(docker ps | grep )" ] && docker run -d --name – David Apr 16 '17 at 02:27
  • 3
    WiRai's answer is shorter and suffers from no grep-related issues – erik258 Nov 14 '17 at 21:20
  • As a note, `docker ps` is an alias for `docker container ls`. – lmat - Reinstate Monica Jul 17 '18 at 20:31
  • 3
    `docker ps -aq -f name=^name$` will match only the exact name – Olix Oct 05 '20 at 14:22
56

I suppose

docker container inspect <container-name> || docker run...

since docker container inspect call will set $? to 1 if container does not exist (cannot inspect) but to 0 if it does exist (this respects stopped containers). So the run command will just be called in case container does not exist as expected.

WiRai
  • 711
  • 5
  • 6
  • 21
    I'd even go with `docker container inspect > /dev/null 2>&1` to discard both successful and unsuccessful output. – Mikhail Vasin Feb 24 '18 at 11:13
  • This is actually the more practical/less error-prone answer; typically it's better to rely on exit codes than text processing since text output is more likely to change over versions. – Gerard van Helden Apr 27 '23 at 15:24
41

You can use filter and format options for docker ps command to avoid piping with unix utilities like grep, awk etc.

name='nginx'

[[ $(docker ps --filter "name=^/$name$" --format '{{.Names}}') == $name ]] ||
docker run -d --name mynginx <nginx-image>
anubhava
  • 761,203
  • 64
  • 569
  • 643
  • 6
    This will match on a partial string, but you can get an exact match with `--filter "name=^/$name$"` – bcoughlan Jul 31 '18 at 10:57
  • @bcoughlan where is it documented? anubhava: https://stackoverflow.com/a/43202632/895245 had already mentioned it previously, you should like to that. – Ciro Santilli OurBigBook.com Aug 28 '18 at 07:39
  • 2
    @CiroSantilli新疆改造中心六四事件法轮功 It doesn't seem to be documented in the docker ps documentation. The string is interpreted by Docker as a regex, the '/' character is in the name, although I'm not sure if/why the first `$` is needed. – bcoughlan Aug 28 '18 at 08:16
  • 3
    @bcoughlan The first `$` is to replace `name` with the value of the shell variable called `name`. The variable is defined just before. `"name=^/$name$"` is equivalent to `"name=^/${name}$"` (the latter is much more readable IMO). – fstamour Oct 28 '22 at 17:52
26

Just prefix the name with ^/ and suffix with $. It seems that it is a regular expression:

CONTAINER_NAME='mycontainername'

CID=$(docker ps -q -f status=running -f name=^/${CONTAINER_NAME}$)
if [ ! "${CID}" ]; then
  echo "Container doesn't exist"
fi
unset CID
yucer
  • 4,431
  • 3
  • 34
  • 42
22

Even shorter with docker top:

docker top <name> || docker run --name <name> <image>

docker top returns non-zero when there are no containers matching the name running, else it returns the pid, user, running time and command.

Blaise
  • 13,139
  • 9
  • 69
  • 97
  • Little note: the question was "if exists" not "if runs"...I used your solution not thinking about that my container can be stopped at that point in time...seems like I have to do inspect even if top is shorter – andymel Oct 02 '22 at 11:54
11

Robust grep ^$ without undocumented behavior

This is the most precise and flexible approach I could find:

container_name=mycont
if sudo docker ps -a --format '{{.Names}}' | grep -Eq "^${container_name}\$"; then
  echo exists
else
  echo 'does not exist'
fi

Rationale:

  1. https://stackoverflow.com/a/38576401/895245 doesn't work if the container name is a substring in another container
  2. https://stackoverflow.com/a/45171589/895245 and https://stackoverflow.com/a/43202632/895245 rely on behaviors for which I could not find the documentation: the exit status of docker container inspect and that -f name takes regular expressions of some kind.

Python

A Python version for convenience since I ended up using it in a project:

containers = subprocess.check_output([
        'sudo',
        'docker',
        'ps',
        '-a',
        '--format', '{{.Names}}',
]).decode()
if container_name in containers.split():
    # Exists.
Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
9

This is my solution to check for a running container, stop it, then remove it.

CNAME=$CONTAINER_NAME-$CODE_VERSION
if [ "$(docker ps -qa -f name=$CNAME)" ]; then
    echo ":: Found container - $CNAME"
    if [ "$(docker ps -q -f name=$CNAME)" ]; then
        echo ":: Stopping running container - $CNAME"
        docker stop $CNAME;
    fi
    echo ":: Removing stopped container - $CNAME"
    docker rm $CNAME;
fi

I've had to search this too many times because even the 100+ answer above doesn't actually work. I think the reason is a misunderstanding on docker ps. docker ps lists RUNNING containers. docker ps -q does the same but the output is striped to include only the container_id. docker ps -a lists ALL containers (running or not). docker ps -qa then is a simple list of all containers while docker ps -q is a simple list of running containers. docker ps -q -f name=ContainerName is then a simple list of running containers with the name ContainerName. docker ps -qa -f would include exited containers as well so the logic must be to check -a (there, running or not), then without -a to see if it's not only there, but running (and needs to be stopped first).

rainabba
  • 3,804
  • 35
  • 35
  • 1
    These worked perfectly for my use case of: recreating a container every time regardless whether it exists or not. – Vitalis Oct 17 '21 at 08:41
2

I use following code to determine if docker container exists:

CONTAINER_NAME='my_docker_container'
# Checking if docker container with $CONTAINER_NAME name exists.
COUNT=$(docker ps -a | grep "$CONTAINER_NAME" | wc -l)
if (($COUNT > 0)); then
    echo 'container exists'
fi
Aliaksei Maniuk
  • 1,534
  • 2
  • 18
  • 30
  • Fails for substring match, or if other fields of `ps -a` match, and you don't need `wc`, grep status can be used directly. My version does not suffer from those problems: https://stackoverflow.com/a/50841982/895245 – Ciro Santilli OurBigBook.com Aug 28 '18 at 07:43
2

-a if you want to list all states (stopped, running etc.)
-f status=running (no need if you want to list only running containers)

$ docker ps -f name=containerName | grep containerName

If there is 1 or more lines status code of command will be 0. If there is no container, grep will be ended with 1 status code. You can handle it by:

Windows

$ echo %errorlevel%

Linux

$ echo $?

container is up and running

when container is stopped

see the properties of execSync Ref: https://www.cyberciti.biz/faq/linux-bash-exit-status-set-exit-statusin-bash/

uzay95
  • 16,052
  • 31
  • 116
  • 182
1
if [[ $(sudo docker inspect --format . <container-name>) == "." ]]; then
  docker run <container-name>;
fi

Explanation:

There is a similar response already. The difference here is the --format . option (you can also use -f .). This removes all the details from the inspect command. Docker uses the go template format, which in this case means that it will copy to the output anything it does not recognize.

So -f itIsThere will return itIsThere if a container with that namex exits. If it doesn't, docker will return an error code and message (Error: No such object: <container-name>).

I found this one in Jenkins logs.

Fernando César
  • 681
  • 1
  • 8
  • 16
1

Here an example of a docker container existence check by exact name:

(docker ps -a --format {{.Names}} | grep container_name -w) && echo Exists || echo "Doesn't exist"
Gustavo Dias
  • 339
  • 2
  • 6
1

to skip Exited container:-

CONTAINER_NAME=xyz
if [ ! "$(docker ps -a | grep ${CONTAINER_NAME} | grep -v Exited)" ]; then echo "${CONTAINER_NAME} is not running"; else echo "${CONTAINER_NAME} is running"; fi
0

Piggy-backing off of @Fernando César.
This checks for the container id from the given container name and suppresses error output ( 2> /dev/null ).

CONTAINER_NAME="awesome-container"

CONTAINER_ID=$(docker inspect --format="{{.Id}}" ${CONTAINER_NAME} 2> /dev/null)
if [[ "${CONTAINER_ID}" ]]; then
  # container found.
else
  # container not found.
fi
GollyJer
  • 23,857
  • 16
  • 106
  • 174
0

In bash script I check if container exists by name like this :

CONTAINER_NAME="my-container-name"
if ! docker container ls -a | grep -Fq "$CONTAINER_NAME" 1>/dev/null; then
echo "could not found container $CONTAINER_NAME..."
fi
Namig Hajiyev
  • 1,117
  • 15
  • 16