# How to Execute a Command Inside a Running Container Using Apple Container

> Run commands inside live Apple Container instances using `container exec`. Explore TTY, detached mode, and custom user options for flexible container command execution.

- Repository: [Apple/container](https://github.com/apple/container)
- Tags: how-to-guide
- Published: 2026-07-05

---

**Use `container exec <container-name> <command>` to run arbitrary processes inside live containers, with support for interactive TTY, detached mode, and custom users/environments.**

The `apple/container` repository provides a lightweight container runtime for macOS that includes a Docker-compatible `exec` command. When you need to execute a command inside a running container, Apple Container bridges the CLI to the underlying XPC-based sandbox runtime while preserving the original container's isolation guarantees.

## How `container exec` Works Under the Hood

The execution logic resides in [`Sources/ContainerCommands/Container/ContainerExec.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Container/ContainerExec.swift), specifically within the `Application.ContainerExec` struct and its `run()` method. When you invoke `container exec`, the CLI performs a seven-step sequence to spawn a sandboxed process in the target container's namespace.

### Container Lookup and State Validation

First, a `ContainerClient` instance contacts the local container daemon via `client.get(id:)` to fetch container metadata. The helper `ensureRunning(container:)` validates that the container is live before proceeding, raising an error if the target is not running.

### Process Configuration and I/O Setup

The CLI builds a process configuration starting from the container's `initProcess` configuration (`container.configuration.initProcess`). It overrides the executable with your command-line argument, sets arguments, and applies optional flags parsed by `Parser.user` and `Parser.allEnv` for user/group handling and environment variables.

Then, `ProcessIO.create` constructs the appropriate stdin/stdout/stderr pipes, allocating a pseudo-terminal when `--tty` is specified or attaching the host's stdin when `--interactive` is set.

## Execution Modes and Signal Handling

Finally, `client.createProcess` sends the configuration to the container runtime to obtain a `Process` handle. If `--detach` (`-d`) is specified, the process starts in the background and the CLI prints the container ID immediately. Otherwise, the CLI forwards signals like `SIGINT` and `SIGTERM` to the child process, monitors execution, and returns the exit code to your shell.

## Practical Usage Examples

Here are common patterns for executing commands inside running containers:

```bash

# Run a one-off command (list files) inside a running container named "my-web-server"

container exec my-web-server ls /var/www

```

```bash

# Open an interactive shell (TTY + stdin) inside the container

container exec -it my-web-server /bin/bash

```

```bash

# Run a background command inside the container (detached)

container exec -d my-web-server /usr/bin/python3 /opt/app/background_worker.py

```

```bash

# Override the user and group for the executed process

container exec --user nobody --gid 1000 my-web-server cat /etc/passwd

```

```bash

# Set environment variables and a custom working directory

container exec -e DEBUG=1 -w /app my-web-server ./run-tests.sh

```

## Key Implementation Files

Understanding these core files helps when debugging or extending exec functionality:

- **[`Sources/ContainerCommands/Container/ContainerExec.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Container/ContainerExec.swift)** – Implements the `container exec` command logic, including argument parsing and the `run()` method that orchestrates process creation.
- **[`Sources/ContainerAPIClient/ContainerClient.swift`](https://github.com/apple/container/blob/main/Sources/ContainerAPIClient/ContainerClient.swift)** – Provides the client interface to the container daemon, used by `exec` to fetch containers and create processes.
- **[`Sources/ContainerBuild/ProcessIO.swift`](https://github.com/apple/container/blob/main/Sources/ContainerBuild/ProcessIO.swift)** – Helper for constructing stdio streams, handling TTY allocation and interactive mode.
- **[`Sources/ContainerPlugin/Parser.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPlugin/Parser.swift)** – Parses environment-file (`--env-file`) and user/group flags for process configuration.
- **[`docs/command-reference.md`](https://github.com/apple/container/blob/main/docs/command-reference.md)** – Official documentation for `container exec` syntax and options.

## Summary

- **`container exec`** is the primary CLI command for running processes inside live Apple Containers.
- The implementation in [`ContainerExec.swift`](https://github.com/apple/container/blob/main/ContainerExec.swift) validates container state, builds process configurations, and handles I/O through `ProcessIO.create`.
- You can run commands in **attached** mode (default) with signal forwarding and exit code propagation, or **detached** mode (`-d`) for background tasks.
- Interactive features like TTY (`-t`) and stdin attachment (`-i`) reuse the same sandboxing guarantees as the original container process.
- User permissions, environment variables, and working directories can be overridden per-command using flags parsed by [`Parser.swift`](https://github.com/apple/container/blob/main/Parser.swift).

## Frequently Asked Questions

### How do I run an interactive shell inside a running Apple Container?

Use the `-i` (interactive) and `-t` (TTY) flags together: `container exec -it my-web-server /bin/bash`. This allocates a pseudo-terminal and attaches your stdin, allowing you to interact with the shell as if you were running locally.

### What is the difference between detached and attached exec mode?

Attached mode (default) forwards signals from your terminal to the container process and waits for completion, returning the exit code. Detached mode (`-d`) starts the process in the background via `client.createProcess`, prints the container ID immediately, and exits without waiting for the command to finish.

### How does Apple Container handle user and group permissions for exec commands?

The [`Parser.swift`](https://github.com/apple/container/blob/main/Parser.swift) module parses `--user` and `--gid` flags to override the process owner. If unspecified, the command runs with the same user context as the container's original init process, preserving the sandbox's security boundaries.

### Can I set environment variables when executing a command in a running container?

Yes. Use the `-e` flag to set individual variables (e.g., `-e DEBUG=1`) or `--env-file` to load from a file. The `Parser.allEnv` logic in [`ContainerExec.swift`](https://github.com/apple/container/blob/main/ContainerExec.swift) merges these with the container's existing environment before spawning the process.