# How to Execute a Command in a Running Container with Apple Container

> Execute commands in a running Apple Container effortlessly. Learn to use the container exec sub-command to run processes inside live containers via the Container API.

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

---

**Apple Container provides the `container exec` sub-command to run arbitrary processes inside live containers by leveraging the Container API to spawn sandboxed processes within the target container's namespace.**

Apple Container's `container exec` command bridges the gap between the CLI and the underlying XPC-based runtime, allowing you to execute a command in a running container while preserving the same isolation guarantees as the original init process. This functionality is implemented in the open-source `apple/container` repository and reuses the same process-configuration plumbing as the `run` command, making it straightforward to debug, inspect, or extend active workloads.

## The Execution Pipeline

When you invoke `container exec`, the CLI performs a seven-step runtime flow defined in [`Sources/ContainerCommands/Container/ContainerExec.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Container/ContainerExec.swift):

1. **Container Lookup** – A `ContainerClient` instance contacts the local container daemon and fetches container metadata via `client.get(id:)`.

2. **State Validation** – The `ensureRunning(container:)` method verifies the container is active; otherwise, it raises an error.

3. **Configuration Building** – The CLI starts from the container's init process configuration (`container.configuration.initProcess`) and overrides the executable, arguments, and optional flags including TTY allocation, interactive stdin, environment variables, working directory, and user/group handling.

4. **I/O Setup** – `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.

5. **Process Spawn** – `client.createProcess` transmits the configuration to the runtime, returning a `Process` handle.

6. **Detachment** – If `--detach` (`-d`) is provided, the process starts in the background and the CLI prints the container ID without waiting.

7. **Synchronous Monitoring** – Otherwise, the CLI forwards signals (SIGINT, SIGTERM) to the child process, monitors completion, and returns the exit code to the shell.

## Implementation Details

The command definition and argument parsing reside in the `ContainerExec` struct (lines 23-45 of [`Sources/ContainerCommands/Container/ContainerExec.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Container/ContainerExec.swift)), while the execution logic lives in the `run()` method (lines 46-114). User and group overrides are parsed by `Parser.user` in [`Sources/ContainerPlugin/Parser.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPlugin/Parser.swift), and environment variable handling flows through `Parser.allEnv`. The `ContainerClient` class in [`Sources/ContainerAPIClient/ContainerClient.swift`](https://github.com/apple/container/blob/main/Sources/ContainerAPIClient/ContainerClient.swift) provides the daemon communication layer, and [`Sources/ContainerBuild/ProcessIO.swift`](https://github.com/apple/container/blob/main/Sources/ContainerBuild/ProcessIO.swift) manages stream allocation. User-facing documentation appears in [`docs/command-reference.md`](https://github.com/apple/container/blob/main/docs/command-reference.md) (lines 52-71).

## Practical Examples

Run a one-off command inside a running container named "my-web-server":

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

```

Open an interactive shell with TTY and stdin attached:

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

```

Run a background command in detached mode:

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

```

Override the user and group for the executed process:

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

```

Set environment variables and a custom working directory:

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

```

## Summary

- **Use `container exec`** to run arbitrary processes inside already-running Apple Containers without creating new instances.
- **Configuration inheritance** leverages the container's init process settings while allowing overrides for executables, arguments, users, groups, and environments.
- **Interactive support** via `-i` and `-t` flags allocates pseudo-terminals and attaches stdin for shell sessions.
- **Background execution** using `-d` detaches the process and returns immediately with the container ID.
- **Isolation preservation** ensures all executed commands maintain the same sandboxing guarantees as the original container process.

## Frequently Asked Questions

### How does container exec differ from container run?

`container run` creates a new container instance from an image, whereas `container exec` injects a process into an existing running container's namespace. The exec command uses `ContainerClient.get(id:)` to look up the live container and calls `ensureRunning(container:)` to validate state before spawning, ensuring you target active workloads rather than initializing fresh ones.

### Can I run interactive commands like bash through container exec?

Yes. Pass the `-i` (interactive) and `-t` (TTY) flags to attach your terminal's stdin and allocate a pseudo-terminal. According to the implementation in [`ContainerExec.swift`](https://github.com/apple/container/blob/main/ContainerExec.swift), this triggers `ProcessIO.create` to configure the appropriate streams, allowing you to execute `container exec -it my-container /bin/bash` for full shell access inside the sandbox.

### What happens if the container is stopped when I try to exec?

The `ensureRunning(container:)` validation step checks the container state before process creation. If the target container is not running, the CLI raises an error and exits without attempting to create the process, preventing execution attempts against inactive containers.

### How do I set environment variables when executing a command?

Use the `-e` flag followed by `KEY=VALUE` pairs, or specify an environment file with `--env-file`. The [`Parser.swift`](https://github.com/apple/container/blob/main/Parser.swift) file handles these inputs through `Parser.allEnv`, merging them into the process configuration that overrides the container's base environment for that specific execution.