Created
August 18, 2025 08:34
-
-
Save akirak/19fe1ff2b20e5541b06c13d2e74a6359 to your computer and use it in GitHub Desktop.
A shell script to recursively remove podman containers that depend on an image. Useful for cleaning up images on NixOS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# Script to recursively remove podman images and their dependent containers | |
# Usage: ./podman_recursive_rm.sh <image_id_or_name> [max_iterations] | |
set -e | |
# Colors for output | |
RED='\033[0;31m' | |
GREEN='\033[0;32m' | |
YELLOW='\033[1;33m' | |
BLUE='\033[0;34m' | |
NC='\033[0m' # No Color | |
# Function to print colored output | |
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } | |
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; } | |
log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; } | |
log_error() { echo -e "${RED}[ERROR]${NC} $1"; } | |
# Function to extract container ID from error message | |
extract_container_id() { | |
local error_msg="$1" | |
# Extract the container ID from the error message | |
# Pattern matches 64-char or 12-char hex strings (full or short container IDs) | |
echo "$error_msg" | grep -oE '[a-f0-9]{64}|[a-f0-9]{12}' | head -n1 | |
} | |
# Main recursive removal function | |
recursive_remove() { | |
local image_id="$1" | |
local max_iterations="$2" | |
local iteration=1 | |
log_info "Starting recursive removal of image: $image_id (max iterations: $max_iterations)" | |
while [[ $iteration -le $max_iterations ]]; do | |
log_info "=== Iteration $iteration/$max_iterations ===" | |
# Try to remove the image | |
log_info "Attempting to remove image: $image_id" | |
local output | |
local exit_code=0 | |
output=$(podman image rm "$image_id" 2>&1) || exit_code=$? | |
if [[ $exit_code -eq 0 ]]; then | |
log_success "Successfully removed image: $image_id" | |
echo "$output" | |
return 0 | |
fi | |
# Check if the error is about container dependencies | |
if echo "$output" | grep -q "image.*used by\|image is in use by a container"; then | |
log_warning "Image is in use by containers" | |
echo "$output" | |
# Extract container ID from error message | |
local container_id | |
container_id=$(extract_container_id "$output") | |
if [[ -n "$container_id" ]]; then | |
log_info "Found dependent container: $container_id" | |
log_info "Removing container: $container_id" | |
if podman container rm "$container_id"; then | |
log_success "Successfully removed container: $container_id" | |
else | |
log_error "Failed to remove container: $container_id" | |
return 1 | |
fi | |
else | |
log_error "Could not extract container ID from error message" | |
return 1 | |
fi | |
else | |
log_error "Image removal failed with error:" | |
echo "$output" | |
return $exit_code | |
fi | |
((iteration++)) | |
done | |
log_error "Failed to remove image after $max_iterations iterations" | |
return 1 | |
} | |
# Function to show usage | |
show_usage() { | |
echo "Usage: $0 <image_id_or_name> [max_iterations]" | |
echo "" | |
echo "Arguments:" | |
echo " image_id_or_name Image ID or name to remove" | |
echo " max_iterations Maximum iterations (default: 10)" | |
echo "" | |
echo "Examples:" | |
echo " $0 nginx:latest" | |
echo " $0 3c7c1348fe6e 5" | |
echo " $0 myimage:v1.0" | |
} | |
# Main script | |
main() { | |
local image_id="$1" | |
local max_iterations="${2:-10}" | |
# Validate arguments | |
if [[ -z "$image_id" ]]; then | |
log_error "Image ID or name is required" | |
show_usage | |
exit 1 | |
fi | |
if [[ "$image_id" == "-h" || "$image_id" == "--help" ]]; then | |
show_usage | |
exit 0 | |
fi | |
if ! [[ "$max_iterations" =~ ^[0-9]+$ ]] || [[ "$max_iterations" -lt 1 ]]; then | |
log_error "Invalid iteration count: $max_iterations" | |
exit 1 | |
fi | |
# Check if podman is available | |
if ! command -v podman &> /dev/null; then | |
log_error "podman command not found" | |
exit 1 | |
fi | |
# Check if image exists | |
if ! podman image exists "$image_id" 2>/dev/null; then | |
log_error "Image does not exist: $image_id" | |
exit 1 | |
fi | |
log_info "Configuration: Image=$image_id, Max iterations=$max_iterations" | |
# Run the recursive removal | |
if recursive_remove "$image_id" "$max_iterations"; then | |
log_success "Image and dependent containers removed successfully!" | |
exit 0 | |
else | |
log_error "Failed to remove image and/or containers" | |
exit 1 | |
fi | |
} | |
# Run main function with all arguments | |
main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment