docker exec runs a command inside an already-running container. It is the second-most-typed Docker command after docker run, and it is what you reach for when you want to look inside a database, install a tool inside a long-running container temporarily, or just check why something is misbehaving without restarting it.
How do I shell into a running Docker container?
docker exec -it CONTAINER_NAME bashThat is the canonical command. -it allocates an interactive TTY, CONTAINER_NAME is the name (or ID prefix) of a running container, and bash is the shell to start. If the image is Alpine-based (or anything else without bash), use sh instead: docker exec -it CONTAINER_NAME sh. To shell in as root when the image runs as a non-root user: add -u root (or --user root).
The shape of docker exec
docker exec [FLAGS] CONTAINER_NAME COMMAND [ARGS...]Everything after the container name is the command run inside it. Flags before, command after.
Jump to:
- Interactive shell vs one-shot command
- bash, sh, and the alpine question
- Run as a different user
- Working directory and env vars
- Detached exec
- Common patterns
- docker exec vs docker run vs docker attach
- FAQ
Interactive shell vs one-shot command
# Interactive shell
docker exec -it CONTAINER bash
# One-shot command (no shell needed)
docker exec CONTAINER ls -la /app
# One-shot with pipes (run inside a shell, since pipes are a shell feature)
docker exec CONTAINER sh -c 'cat /etc/hosts | grep app'-it is for interactive sessions where you type. Without -it, exec runs the command and exits — perfect for scripting (docker exec CONTAINER /healthcheck.sh).
For piped commands, remember that |, >, and && are shell features. docker exec CONTAINER cat /etc/hosts | grep app runs cat /etc/hosts inside the container and pipes the output through grep on the host. To run the whole pipe inside the container, wrap it: docker exec CONTAINER sh -c 'cat /etc/hosts | grep app'.
bash, sh, and the alpine question
# Most images: bash exists
docker exec -it CONTAINER bash
# Alpine, distroless, scratch-based: bash often does NOT exist
docker exec -it CONTAINER sh
# Cover both: try bash, fall back to sh
docker exec -it CONTAINER sh -c 'command -v bash >/dev/null && exec bash || exec sh'The error you get on alpine when you ask for bash:
OCI runtime exec failed: exec failed: unable to start container process:
exec: "bash": executable file not found in $PATH: unknown
Always reach for sh first when the base image is alpine, busybox, or anything labeled "distroless". sh (BusyBox ash on Alpine) is more limited than bash but enough for inspection.
Distroless images sometimes have no shell at all — those need a debug variant (gcr.io/distroless/.../debug) or you have to use kubectl debug / docker debug style workflows. If you find yourself frequently exec'ing into a container that has no shell, the container is doing its job; you should be debugging from outside (logs, metrics).
Run as a different user
# Run as a specific user (UID:GID)
docker exec -it -u 1000:1000 CONTAINER bash
# Run as a named user that exists in /etc/passwd inside the container
docker exec -it -u root CONTAINER bash
# Run as root to install a package in a non-root container temporarily
docker exec -it -u root CONTAINER apk add curl-u (or --user) overrides which user the command runs as. The most common use is -u root to install a debugging tool inside a non-root container — the image ships running as node or app, and you need apt install strace (which requires root). After you're done, the next exec without -u drops back to the image's default user.
The reverse is less common but exists: dropping privileges further with -u nobody:nobody to test what an unprivileged process would see.
Working directory and env vars
# Working directory inside the container
docker exec -it -w /var/log CONTAINER ls
# Set env vars for the exec'd command
docker exec -it -e DEBUG=1 CONTAINER ./run-tests.sh
# Env from a file
docker exec -it --env-file ./debug.env CONTAINER bashThese match the docker run equivalents. -w is convenient when the container's default WORKDIR is somewhere other than where you want to be.
Detached exec
# Start a long-running task inside a container, don't block your terminal
docker exec -d CONTAINER bash -c 'while true; do echo tick; sleep 1; done >> /tmp/ticks.log'-d runs the command in the background. Useful for kicking off a long-running job inside a service without blocking your shell. Rare in practice — usually if you need a long-running process, it should be in its own container.
Common patterns
Connect to a database inside a container:
# MySQL
docker exec -it db mysql -u root -p
# PostgreSQL
docker exec -it db psql -U postgres
# Redis
docker exec -it cache redis-cli
# MongoDB
docker exec -it db mongoshTail a log file from inside the container:
docker exec -it CONTAINER tail -f /var/log/app.log(Prefer docker logs -f CONTAINER if the app logs to stdout — see docker logs.)
Run a script that lives inside the image:
docker exec CONTAINER /usr/local/bin/healthcheck.shInspect environment variables inside the container:
docker exec CONTAINER env
docker exec CONTAINER printenv DATABASE_URLRun a quick test command without saving anything:
docker exec CONTAINER python -c 'import sys; print(sys.version)'Open a shell as root in a non-root container to install a tool:
docker exec -it -u root CONTAINER apk add --no-cache curl jqThe tool persists for the lifetime of that container. The image is unchanged; if you remove and recreate the container, the tool is gone. For permanent additions, edit the Dockerfile.
docker exec vs docker run vs docker attach
Three commands that sound similar; they do different things.
| Command | What it does | When to use |
|---|---|---|
docker run | Creates a new container from an image and starts it | Starting a service or one-shot |
docker exec | Runs a command inside an existing running container | Inspecting / debugging a running service |
docker attach | Connects your terminal to the running container's main process (stdin/stdout) | Watching a foreground process; rarely the right answer |
docker attach connects to the container's main process directly. If that process is a shell, you can type into it; if it's a server, you mostly just watch it log. Detaching from attach without killing the container needs the escape sequence (Ctrl-P Ctrl-Q), which is awkward. exec is almost always what you actually want — it starts a new process inside the container and exiting it doesn't affect the main process.
FAQ
Sources
Authoritative references this article was fact-checked against.
- docker exec — official CLI referencedocs.docker.com

