diff --git a/Docker容器管理面板 b/Docker容器管理面板 index d6882b3..75582fb 100644 --- a/Docker容器管理面板 +++ b/Docker容器管理面板 @@ -7,6 +7,7 @@ RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' +PURPLE='\033[0;35m' NC='\033[0m' # 检查 Docker @@ -46,6 +47,35 @@ show_containers() { echo } +# 显示镜像列表 +show_images() { + echo -e "\n${PURPLE}=== 镜像列表 ===${NC}" + echo "编号 | 镜像名称:标签 | 镜像ID | 大小 | 创建时间" + echo "----|---------------|--------|------|----------" + + local count=0 + docker images --format "table {{.Repository}}:{{.Tag}}\t{{.ID}}\t{{.Size}}\t{{.CreatedSince}}" | tail -n +2 | while read line; do + if [ -n "$line" ]; then + count=$((count + 1)) + repo_tag=$(echo "$line" | awk '{print $1}') + image_id=$(echo "$line" | awk '{print $2}') + size=$(echo "$line" | awk '{print $3}') + created=$(echo "$line" | awk '{for(i=4;i<=NF;i++) printf $i" "; print ""}' | sed 's/ $//') + + # 截断过长的镜像名称 + if [ ${#repo_tag} -gt 25 ]; then + repo_tag="${repo_tag:0:22}..." + fi + + # 截断镜像ID + image_id_short="${image_id:0:12}" + + echo -e "$count | $repo_tag | $image_id_short | $size | $created" + fi + done + echo +} + # 通过编号获取容器名称 get_container_name() { local number=$1 @@ -60,6 +90,20 @@ get_container_name() { done } +# 通过编号获取镜像ID +get_image_id() { + local number=$1 + local count=0 + docker images --format "table {{.ID}}" | tail -n +2 | while read image_id; do + if [ -n "$image_id" ]; then + count=$((count + 1)) + if [ $count -eq $number ]; then + echo "$image_id" + fi + fi + done +} + # 批量删除容器 batch_delete_containers() { local numbers="$1" @@ -111,6 +155,151 @@ batch_delete_containers() { fi } +# 批量删除镜像 +batch_delete_images() { + local numbers="$1" + local confirm="$2" + + # 处理输入,支持空格和逗号分隔 + numbers=$(echo "$numbers" | sed 's/,/ /g') + + local success_count=0 + local fail_count=0 + + for number in $numbers; do + if [[ "$number" =~ ^[0-9]+$ ]]; then + image_id=$(get_image_id $number) + if [ -n "$image_id" ]; then + # 获取镜像名称用于显示 + image_name=$(docker images --format "table {{.Repository}}:{{.Tag}}\t{{.ID}}" | grep "$image_id" | awk '{print $1}') + + if [ "$confirm" != "y" ]; then + echo -e "${YELLOW}删除镜像: $image_name${NC}" + read -p "确认删除?(Y/n): " confirm_delete + confirm_delete=${confirm_delete:-Y} # 默认Y + if [[ "$confirm_delete" != "y" && "$confirm_delete" != "Y" ]]; then + echo -e "${GREEN}跳过: $image_name${NC}" + continue + fi + fi + + if docker rmi "$image_id" &> /dev/null; then + echo -e "${GREEN}✓ 删除成功: $image_name${NC}" + success_count=$((success_count + 1)) + else + echo -e "${RED}✗ 删除失败: $image_name (可能有容器在使用此镜像)${NC}" + fail_count=$((fail_count + 1)) + fi + else + echo -e "${RED}✗ 镜像编号不存在: $number${NC}" + fail_count=$((fail_count + 1)) + fi + else + echo -e "${RED}✗ 无效编号: $number${NC}" + fail_count=$((fail_count + 1)) + fi + done + + echo + if [ $success_count -gt 0 ]; then + echo -e "${GREEN}成功删除 $success_count 个镜像${NC}" + fi + if [ $fail_count -gt 0 ]; then + echo -e "${RED}删除失败 $fail_count 个${NC}" + fi +} + +# 清理悬空镜像 +clean_dangling_images() { + echo -e "${YELLOW}清理悬空镜像...${NC}" + local dangling_count=$(docker images -f "dangling=true" -q | wc -l) + if [ $dangling_count -gt 0 ]; then + read -p "确认删除 $dangling_count 个悬空镜像?(Y/n): " confirm_dangling + confirm_dangling=${confirm_dangling:-Y} + if [[ "$confirm_dangling" == "y" || "$confirm_dangling" == "Y" ]]; then + docker image prune -f + echo -e "${GREEN}已清理 $dangling_count 个悬空镜像${NC}" + else + echo -e "${GREEN}取消清理${NC}" + fi + else + echo -e "${GREEN}没有悬空镜像${NC}" + fi +} + +# 镜像管理菜单 +image_management() { + while true; do + clear + echo -e "${PURPLE}" + echo "========================================" + echo " Docker 镜像管理" + echo "========================================" + echo -e "${NC}" + + show_images + + echo -e "${PURPLE}镜像操作选项:${NC}" + echo "1. 删除镜像 (支持批量: 1 2 3 或 1,2,3)" + echo "2. 批量删除所有镜像" + echo "3. 清理悬空镜像" + echo "4. 返回主菜单" + echo + + read -p "请选择操作: " choice + + case $choice in + 1) + echo + echo -e "${YELLOW}删除镜像 (支持批量删除)${NC}" + echo "输入单个编号: 1" + echo "输入多个编号: 1 2 3 或 1,2,3" + echo "输入 all 删除所有镜像" + read -p "请输入镜像编号: " input + + if [[ "$input" == "all" ]]; then + echo -e "${RED}警告:将删除所有镜像!${NC}" + read -p "确认删除所有镜像?(Y/n): " confirm_all + confirm_all=${confirm_all:-Y} + if [[ "$confirm_all" == "y" || "$confirm_all" == "Y" ]]; then + total_count=$(docker images -q | wc -l) + docker rmi -f $(docker images -q) &> /dev/null + echo -e "${GREEN}已删除所有 $total_count 个镜像${NC}" + else + echo -e "${GREEN}取消删除${NC}" + fi + else + batch_delete_images "$input" "n" + fi + ;; + 2) + echo -e "${RED}警告:将删除所有镜像!${NC}" + read -p "确认删除所有镜像?(Y/n): " confirm_all + confirm_all=${confirm_all:-Y} + if [[ "$confirm_all" == "y" || "$confirm_all" == "Y" ]]; then + total_count=$(docker images -q | wc -l) + docker rmi -f $(docker images -q) &> /dev/null + echo -e "${GREEN}已删除所有 $total_count 个镜像${NC}" + else + echo -e "${GREEN}取消删除${NC}" + fi + ;; + 3) + clean_dangling_images + ;; + 4) + return + ;; + *) + echo -e "${RED}无效选择${NC}" + ;; + esac + + echo + read -p "按回车键继续..." + done +} + # 主菜单 main_menu() { while true; do @@ -123,13 +312,15 @@ main_menu() { show_containers - echo -e "${BLUE}操作选项:${NC}" + echo -e "${BLUE}容器操作选项:${NC}" echo "1. 启动容器" echo "2. 停止容器" echo "3. 重启容器" echo "4. 删除容器 (支持批量: 1 2 3 或 1,2,3)" echo "5. 批量删除所有已停止容器" echo "6. 查看容器日志" + echo -e "${PURPLE}镜像操作选项:${NC}" + echo "7. 查看和管理镜像" echo "0. 退出" echo @@ -185,7 +376,7 @@ main_menu() { if [[ "$input" == "all" ]]; then echo -e "${RED}警告:将删除所有容器!${NC}" read -p "确认删除所有容器?(Y/n): " confirm_all - confirm_all=${confirm_all:-Y} # 默认Y + confirm_all=${confirm_all:-Y} if [[ "$confirm_all" == "y" || "$confirm_all" == "Y" ]]; then total_count=$(docker ps -aq | wc -l) docker rm -f $(docker ps -aq) &> /dev/null @@ -194,7 +385,7 @@ main_menu() { echo -e "${GREEN}取消删除${NC}" fi else - batch_delete_containers "$input" "n" # 第二个参数"n"表示需要单独确认 + batch_delete_containers "$input" "n" fi ;; 5) @@ -202,7 +393,7 @@ main_menu() { stopped_count=$(docker ps -aq -f status=exited | wc -l) if [ $stopped_count -gt 0 ]; then read -p "确认删除 $stopped_count 个已停止容器?(Y/n): " confirm_stopped - confirm_stopped=${confirm_stopped:-Y} # 默认Y + confirm_stopped=${confirm_stopped:-Y} if [[ "$confirm_stopped" == "y" || "$confirm_stopped" == "Y" ]]; then docker rm $(docker ps -aq -f status=exited) &> /dev/null echo -e "${GREEN}已删除 $stopped_count 个已停止容器${NC}" @@ -213,6 +404,9 @@ main_menu() { echo -e "${GREEN}没有已停止的容器${NC}" fi ;; + 7) + image_management + ;; 0) echo echo -e "${GREEN}再见!${NC}"