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

> Learn how to execute commands in a running Apple Container using the container exec command. Run arbitrary processes inside live containers with ease and efficiency.

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

---

**Apple Container provides the `container exec` sub-command to run arbitrary processes inside live containers by creating a new sandboxed process in the target container's namespace.**

The `apple/container` repository implements a modern container runtime for macOS that allows you to execute commands in already-running containers without interrupting the main process. This capability is essential for debugging, administration, and maintenance tasks that require access to a container's internal environment.

## The `container exec` Command Structure

The `container exec` command re-uses the same process-configuration plumbing as `container run`, but targets an existing container rather than creating a new one. When you invoke this command, the CLI performs a sequence of operations defined in [`Sources/ContainerCommands/Container/ContainerExec.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Container/ContainerExec.swift)【 L23-L45 】.

The basic syntax follows this pattern:

```bash
container exec [OPTIONS] CONTAINER COMMAND [ARG...]

```

The command accepts several flags to control execution behavior:
- `-i, --interactive` – Keep stdin open
- `-t, --tty` – Allocate a pseudo-TTY
- `-d, --detach` – Run command in background
- `-u, --user` – Specify username or UID
- `-g, --gid` – Specify group ID
- `-e, --env` – Set environment variables
- `-w, --workdir` – Set working directory

## Internal Execution Flow

The implementation in [`ContainerExec.swift`](https://github.com/apple/container/blob/main/ContainerExec.swift) handles the entire lifecycle of executing commands in running containers through the following stages:

### Container Lookup and Validation

First, the CLI establishes a `ContainerClient` connection to the local container daemon and fetches container metadata using `client.get(id:)`【 L46-L114 】. The `ensureRunning(container:)` function validates that the target container is active; if the container is stopped or non-existent, the command raises an error immediately.

### Process Configuration Building

The execution logic starts from the container's existing init process configuration (`container.configuration.initProcess`) and overrides specific fields:

- **Executable**: Replaced with the command supplied on the CLI
- **Arguments**: Populated with remaining command-line arguments
- **User/Group**: Modified via `Parser.user` and `Parser.allEnv` from [`Sources/ContainerPlugin/Parser.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPlugin/Parser.swift) when flags are provided
- **Environment**: Merged with variables from `-e` flags and optional env files

### I/O Setup and Process Creation

The `ProcessIO.create` method (defined in [`Sources/ContainerBuild/ProcessIO.swift`](https://github.com/apple/container/blob/main/Sources/ContainerBuild/ProcessIO.swift)) constructs the appropriate stdin/stdout/stderr pipes. When `--tty` is specified, it allocates a pseudo-terminal; when `--interactive` is set, it attaches the host's stdin stream.

Finally, `client.createProcess` transmits the configuration to the container runtime and returns a `Process` handle. If `--detach` is specified, the CLI prints the process ID and exits immediately. Otherwise, it forwards signals (such as `SIGINT` and `SIGTERM`) to the child process, monitors execution, and returns the exit code to the shell.

## Practical Usage Examples

The [`docs/command-reference.md`](https://github.com/apple/container/blob/main/docs/command-reference.md) file【 L52-L71 】documents several common patterns for executing commands in running containers.

### Run One-Off Commands

Execute a single command and return the output:

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

```

### Interactive Shell Access

Open a bash shell with TTY allocation and interactive stdin:

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

```

### Background Execution

Run long-running tasks without blocking the terminal:

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

```

### Override Security Context

Execute commands as a different user or group:

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

```

### Custom Environment and Working Directory

Set environment variables and change the working directory:

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

```

## Summary

- **`container exec`** is the primary interface for running commands in existing Apple Containers
- The command validates container state via `ensureRunning(container:)` before attempting execution
- Process configuration inherits from the container's init process but allows overrides for executable, arguments, user, group, and environment
- **I/O handling** supports three modes: attached (default), interactive (`-it`), and detached (`-d`)
- All execution logic resides in [`Sources/ContainerCommands/Container/ContainerExec.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Container/ContainerExec.swift), with supporting utilities in [`ContainerClient.swift`](https://github.com/apple/container/blob/main/ContainerClient.swift) and [`ProcessIO.swift`](https://github.com/apple/container/blob/main/ProcessIO.swift)

## Frequently Asked Questions

### How do I run an interactive shell in a container?

Use the `-i` and `-t` flags together to allocate a pseudo-terminal and keep stdin open. For example: `container exec -it my-container /bin/bash`. This provides a fully interactive shell session inside the running container's namespace while preserving all isolation guarantees.

### Can I run background processes with `container exec`?

Yes, add the `-d` or `--detach` flag to run the process in the background. The CLI will print the process ID and exit immediately without waiting for completion. This is useful for starting background workers or services without blocking your terminal session.

### How do I specify a different user when executing commands?

Use the `--user` flag followed by a username or UID, and optionally `--gid` for the group ID. For instance: `container exec --user 1000 --gid 1000 my-container whoami`. This overrides the default user defined in the container configuration for that specific process.

### What happens if the container is not running?

The command will fail with an error before attempting to create the process. The `ensureRunning(container:)` validation check in [`ContainerExec.swift`](https://github.com/apple/container/blob/main/ContainerExec.swift) verifies the container state during the initial lookup phase, ensuring you cannot execute commands in stopped or non-existent containers.