docker exec runs a command inside a container that is already running - most often an interactive shell for poking around. The command you want almost every time is docker exec -it <container> bash (or sh if the image has no bash). The -i keeps stdin open and the -t gives you a terminal, and together they turn a one-shot command into a usable shell. docker exec does not restart the container and does not create a new one; it steps into the process namespace of the one that is live.
The mistake people make first is reaching for docker run when they want docker exec. run starts a new container. exec enters an existing one. If you already have something running and you want to look inside it, exec is the verb.
Table of contents
- The command you actually want
- Running one-off commands without a shell
- Environment, user, and working directory
- exec versus run versus attach
- When exec fails
- How this fits the rest of the stack
- FAQ
The command you actually want
docker exec -it my_api bash
That drops you into an interactive bash shell inside the container named my_api. Break it down:
exec- run a command in a running container.-i- interactive; keep stdin open so you can type.-t- allocate a pseudo-TTY so the shell behaves like a real terminal.my_api- the container name or ID (docker pslists them).bash- the command to run; here, a shell.
If the image is a slim one - alpine, distroless-ish, many official images - bash may not exist. Fall back to sh:
docker exec -it my_api sh
sh is almost always present. bash is a luxury the smaller images skip. When bash gives you executable file not found, that is what happened - try sh before assuming the container is broken.
Running one-off commands without a shell
You do not need an interactive shell for a single command. Drop -it and just run it:
docker exec my_api ls -la /app
docker exec my_api cat /etc/hostname
docker exec my_api python manage.py migrate
This is the clean way to run a migration, check a file, or fire a management command against the live container. The output comes straight back to your terminal and you are not left inside a shell you have to exit.
Use -i without -t when you want to pipe input in:
echo "SELECT 1;" | docker exec -i my_db psql -U postgres
The rule: -it for an interactive session, -i alone for piping, neither for a fire-and-forget command. Adding -t to a non-interactive command in a script is a common cause of the input device is not a TTY errors in CI.
Environment, user, and working directory
exec takes the same environment-shaping flags as run:
docker exec -it -u root my_api bash # enter as root
docker exec -it -w /app my_api bash # start in /app
docker exec -it -e DEBUG=1 my_api python app.py
-u root is the one you reach for most, because many images run as an unprivileged user and you need root to install a debugging tool or read a protected file. -w sets the working directory so you do not have to cd on entry. -e injects an environment variable for that command only.
These do not persist. Anything you install with -u root lives until the container is recreated, then it is gone - which is the point of containers, and also why you should put real dependencies in the image, not exec them in by hand.
exec versus run versus attach
Three commands sound similar and do different things:
docker runcreates and starts a new container. Everyrunis a fresh container.docker execstarts an additional process inside a container that is already running.docker attachconnects your terminal to the container’s main process (PID 1) - its existing stdout and stdin. Detaching cleanly is fiddly, and Ctrl+C may stop the container.
For debugging, exec is almost always what you want, because it gives you a separate shell process that you can exit without touching the main application. attach puts you on the main process itself, which is riskier. If you have ever accidentally killed a container by pressing Ctrl+C, you were probably attached, not exec’d.
When exec fails
A few failures come up repeatedly:
Container is not running-execonly works on a running container. If it exited, there is nothing to enter; checkdocker ps -aand the logs withdocker logs.executable file not found- the shell or command you asked for is not in the image. Tryshinstead ofbash.the input device is not a TTY- you passed-tin a context with no terminal, usually a CI pipeline. Drop the-t.- Permission denied on a file - you are the container’s non-root user. Re-enter with
-u root.
If the container has already crashed, exec cannot help you - there is no process to step into. That is when you go to the logs, or start a throwaway container from the same image with docker run -it <image> sh to inspect the filesystem. Knowing which tool applies to a stopped versus a running container saves a lot of confused minutes.
How this fits the rest of the stack
docker exec is a debugging tool, and needing it a lot is a signal - if you are constantly shelling in to check why something failed, the real gap is logs and health visibility you can see without touching the container. A platform that surfaces build output, run logs, and health in one place is what turns exec from a daily habit into an occasional one. The RunxBuild hosting calculator lays out the service, database, storage, and bandwidth as separate line items, and the RunxBuild dashboard is where the team watches deploys, logs, and restarts as they happen.
Useful related references:
- kubectl exec: Shell into Container, Multi-Container, and Debug
- Container Manager: Docker Desktop, Podman Desktop, Rancher Desktop, and lens
- Container Security Solutions: The Layered Stack Worth Running
- Docker services on RunxBuild
FAQ
What does docker exec do?
It runs a command inside a container that is already running, without restarting or recreating it. The most common use is docker exec -it <container> bash to get an interactive shell for debugging, but it also runs one-off commands like migrations or file checks against the live container.
What is the difference between docker exec and docker run?
docker run creates and starts a brand-new container. docker exec runs a command inside a container that is already running. If something is live and you want to look inside it, use exec; if you want a fresh container, use run.
Why does docker exec bash say executable not found?
The image does not include bash - many slim images ship only sh. Run docker exec -it <container> sh instead. It is not a sign the container is broken, just that bash was left out to keep the image small.
What do the -it flags mean in docker exec?
-i keeps stdin open so you can type, and -t allocates a pseudo-terminal so the shell behaves normally. Together they give you an interactive session. Use -i alone when piping input, and neither for a single fire-and-forget command in a script.
How do I run docker exec as root?
Add -u root: docker exec -it -u root <container> bash. Many images run as an unprivileged user, so you need root to install debugging tools or read protected files. Anything you change this way lasts only until the container is recreated.