Skip to content

Instantly share code, notes, and snippets.

@nperez
Created March 4, 2026 08:10
Show Gist options
  • Select an option

  • Save nperez/4a15ca70f86f7babfb8ff1aa16efb4c0 to your computer and use it in GitHub Desktop.

Select an option

Save nperez/4a15ca70f86f7babfb8ff1aa16efb4c0 to your computer and use it in GitHub Desktop.
Reconstruct a `docker run` command from a running container.
#!/usr/bin/env bash
#
# docker-reconstruct.sh — Reconstruct a `docker run` command from a running container.
# Usage: ./docker-reconstruct.sh <container_name_or_id>
#
set -euo pipefail
if [[ $# -lt 1 ]]; then
echo "Usage: $0 <container_name_or_id>"
exit 1
fi
C="$1"
if ! docker inspect "$C" &>/dev/null; then
echo "Error: Container '$C' not found."
exit 1
fi
i() { docker inspect --format="$1" "$C"; }
IMAGE=$(i '{{.Config.Image}}')
NAME=$(i '{{.Name}}' | sed 's/^\///')
HOSTNAME=$(i '{{.Config.Hostname}}')
USER=$(i '{{.Config.User}}')
WORKING_DIR=$(i '{{.Config.WorkingDir}}')
RESTART=$(i '{{.HostConfig.RestartPolicy.Name}}')
MAX_RETRY=$(i '{{.HostConfig.RestartPolicy.MaximumRetryCount}}')
NETWORK=$(i '{{.HostConfig.NetworkMode}}')
PID_MODE=$(i '{{.HostConfig.PidMode}}')
PRIVILEGED=$(i '{{.HostConfig.Privileged}}')
READONLY=$(i '{{.HostConfig.ReadonlyRootfs}}')
RUNTIME=$(i '{{.HostConfig.Runtime}}')
INIT=$(i '{{.HostConfig.Init}}')
MEMORY=$(i '{{.HostConfig.Memory}}')
CPUS=$(i '{{.HostConfig.NanoCpus}}')
STDIN_OPEN=$(i '{{.Config.OpenStdin}}')
TTY=$(i '{{.Config.Tty}}')
AUTO_REMOVE=$(i '{{.HostConfig.AutoRemove}}')
ARGS=()
ARGS+=(docker run)
ARGS+=(--name "$NAME" -d)
DEFAULT_HOST=$(i '{{slice .Id 0 12}}')
[[ -n "$HOSTNAME" && "$HOSTNAME" != "$DEFAULT_HOST" ]] && ARGS+=(--hostname "$HOSTNAME")
[[ -n "$USER" ]] && ARGS+=(--user "$USER")
[[ -n "$WORKING_DIR" ]] && ARGS+=(--workdir "$WORKING_DIR")
[[ "$STDIN_OPEN" == "true" ]] && ARGS+=(-i)
[[ "$TTY" == "true" ]] && ARGS+=(-t)
[[ "$AUTO_REMOVE" == "true" ]] && ARGS+=(--rm)
[[ "$PRIVILEGED" == "true" ]] && ARGS+=(--privileged)
[[ "$READONLY" == "true" ]] && ARGS+=(--read-only)
[[ "$INIT" == "true" ]] && ARGS+=(--init)
if [[ -n "$RESTART" && "$RESTART" != "no" ]]; then
if [[ "$RESTART" == "on-failure" && "$MAX_RETRY" -gt 0 ]]; then
ARGS+=(--restart "${RESTART}:${MAX_RETRY}")
else
ARGS+=(--restart "$RESTART")
fi
fi
[[ -n "$NETWORK" && "$NETWORK" != "default" ]] && ARGS+=(--network "$NETWORK")
[[ -n "$PID_MODE" ]] && ARGS+=(--pid "$PID_MODE")
[[ -n "$RUNTIME" && "$RUNTIME" != "runc" ]] && ARGS+=(--runtime "$RUNTIME")
[[ "$MEMORY" -gt 0 ]] && ARGS+=(--memory "$MEMORY")
[[ "$CPUS" -gt 0 ]] && ARGS+=(--cpus "$(awk "BEGIN {printf \"%.2f\", $CPUS / 1000000000}")")
# Port bindings
while IFS= read -r port; do
[[ -z "$port" ]] && continue
ARGS+=(-p "$(echo "$port" | sed 's/^://')")
done <<< "$(docker inspect --format='{{range $cp, $b := .HostConfig.PortBindings}}{{range $b}}{{.HostIp}}:{{.HostPort}}:{{$cp}}{{println}}{{end}}{{end}}' "$C")"
# Volume / bind mounts
while IFS= read -r mount; do
[[ -z "$mount" ]] && continue
TYPE=$(echo "$mount" | cut -d'|' -f1)
SRC=$(echo "$mount" | cut -d'|' -f2)
DST=$(echo "$mount" | cut -d'|' -f3)
MODE=$(echo "$mount" | cut -d'|' -f4)
if [[ "$TYPE" == "tmpfs" ]]; then
ARGS+=(--tmpfs "$DST")
else
M="${SRC}:${DST}"
[[ -n "$MODE" ]] && M+=":${MODE}"
ARGS+=(-v "$M")
fi
done <<< "$(docker inspect --format='{{range .Mounts}}{{.Type}}|{{.Source}}|{{.Destination}}|{{.Mode}}{{println}}{{end}}' "$C")"
# Cap add/drop
while IFS= read -r cap; do [[ -n "$cap" ]] && ARGS+=(--cap-add "$cap"); done <<< "$(i '{{range .HostConfig.CapAdd}}{{.}}{{println}}{{end}}')"
while IFS= read -r cap; do [[ -n "$cap" ]] && ARGS+=(--cap-drop "$cap"); done <<< "$(i '{{range .HostConfig.CapDrop}}{{.}}{{println}}{{end}}')"
# Devices
while IFS= read -r dev; do [[ -n "$dev" ]] && ARGS+=(--device "$dev"); done <<< "$(i '{{range .HostConfig.Devices}}{{.PathOnHost}}:{{.PathInContainer}}:{{.CgroupPermissions}}{{println}}{{end}}')"
# Image
ARGS+=("$IMAGE")
# Command args — only if no custom entrypoint (let the image handle it)
ENTRYPOINT=$(i '{{json .Config.Entrypoint}}')
if [[ "$ENTRYPOINT" == "null" || "$ENTRYPOINT" == "[]" ]]; then
CMD_JSON=$(i '{{json .Config.Cmd}}')
if [[ "$CMD_JSON" != "null" && "$CMD_JSON" != "[]" ]]; then
while IFS= read -r arg; do
ARGS+=("$arg")
done <<< "$(echo "$CMD_JSON" | python3 -c "import sys,json
for a in json.load(sys.stdin): print(a)")"
fi
fi
# Output as a properly shell-quoted string, ready for eval
printf '%q ' "${ARGS[@]}"
echo
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment