{"id":1714,"date":"2026-06-10T23:42:32","date_gmt":"2026-06-10T15:42:32","guid":{"rendered":"https:\/\/www.jumoon.top\/?p=1714"},"modified":"2026-06-10T23:42:32","modified_gmt":"2026-06-10T15:42:32","slug":"docker-%e9%95%9c%e5%83%8f%e5%a4%87%e4%bb%bd-%e6%81%a2%e5%a4%8d%e7%ae%a1%e7%90%86%e8%84%9a%e6%9c%ac","status":"publish","type":"post","link":"https:\/\/www.jumoon.top\/?p=1714","title":{"rendered":"Docker \u955c\u50cf\u5907\u4efd\/\u6062\u590d\u7ba1\u7406\u811a\u672c"},"content":{"rendered":"\n<p>\u5e74\u521d\u7684\u65f6\u5019\u505a\u4e86\u4e2a <a href=\"https:\/\/www.jumoon.top\/?p=1554\" target=\"_blank\" rel=\"noreferrer noopener\">\u98de\u725bNAS Docker \u5bb9\u5668\u955c\u50cf\u5907\u4efd<\/a> \u7684\u811a\u672c\uff0c\u5b9e\u9645\u4f7f\u7528\u4e2d\u6709\u4e9b\u4e0d\u65b9\u4fbf\u7684\uff0c\u505a\u4e86\u70b9\u5347\u7ea7\uff0c\u5b9e\u73b0\u6307\u5b9a\u6216\u8005\u6279\u91cf\u5907\u4efd\u5bb9\u5668\u4e2d\u955c\u50cf\uff0c\u81ea\u52a8\u6839\u636e\u9879\u76ee\u6587\u4ef6\u5939\u4e2d\u7684docker-compose.yml(yaml)\u5355\u4e2a\u6216\u8005\u6279\u91cf\u6062\u590d\u9879\u76ee\u3002<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"975\" height=\"678\" src=\"https:\/\/www.jumoon.top\/wp-content\/uploads\/2026\/06\/01\u9009\u62e9docker\u76ee\u5f55.png\" alt=\"\" class=\"wp-image-1715\" srcset=\"https:\/\/www.jumoon.top\/wp-content\/uploads\/2026\/06\/01\u9009\u62e9docker\u76ee\u5f55.png 975w, https:\/\/www.jumoon.top\/wp-content\/uploads\/2026\/06\/01\u9009\u62e9docker\u76ee\u5f55-300x209.png 300w, https:\/\/www.jumoon.top\/wp-content\/uploads\/2026\/06\/01\u9009\u62e9docker\u76ee\u5f55-768x534.png 768w\" sizes=\"auto, (max-width: 975px) 100vw, 975px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"566\" src=\"https:\/\/www.jumoon.top\/wp-content\/uploads\/2026\/06\/02\u6279\u91cf\u914d\u5907-1024x566.png\" alt=\"\" class=\"wp-image-1716\" srcset=\"https:\/\/www.jumoon.top\/wp-content\/uploads\/2026\/06\/02\u6279\u91cf\u914d\u5907-1024x566.png 1024w, https:\/\/www.jumoon.top\/wp-content\/uploads\/2026\/06\/02\u6279\u91cf\u914d\u5907-300x166.png 300w, https:\/\/www.jumoon.top\/wp-content\/uploads\/2026\/06\/02\u6279\u91cf\u914d\u5907-768x425.png 768w, https:\/\/www.jumoon.top\/wp-content\/uploads\/2026\/06\/02\u6279\u91cf\u914d\u5907.png 1228w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"624\" src=\"https:\/\/www.jumoon.top\/wp-content\/uploads\/2026\/06\/03\u5907\u4efd\u5355\u4e2a-1024x624.png\" alt=\"\" class=\"wp-image-1717\" srcset=\"https:\/\/www.jumoon.top\/wp-content\/uploads\/2026\/06\/03\u5907\u4efd\u5355\u4e2a-1024x624.png 1024w, https:\/\/www.jumoon.top\/wp-content\/uploads\/2026\/06\/03\u5907\u4efd\u5355\u4e2a-300x183.png 300w, https:\/\/www.jumoon.top\/wp-content\/uploads\/2026\/06\/03\u5907\u4efd\u5355\u4e2a-768x468.png 768w, https:\/\/www.jumoon.top\/wp-content\/uploads\/2026\/06\/03\u5907\u4efd\u5355\u4e2a.png 1233w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"763\" src=\"https:\/\/www.jumoon.top\/wp-content\/uploads\/2026\/06\/04\u5355\u4e2a\u6062\u590d-1024x763.png\" alt=\"\" class=\"wp-image-1718\" srcset=\"https:\/\/www.jumoon.top\/wp-content\/uploads\/2026\/06\/04\u5355\u4e2a\u6062\u590d-1024x763.png 1024w, https:\/\/www.jumoon.top\/wp-content\/uploads\/2026\/06\/04\u5355\u4e2a\u6062\u590d-300x224.png 300w, https:\/\/www.jumoon.top\/wp-content\/uploads\/2026\/06\/04\u5355\u4e2a\u6062\u590d-768x572.png 768w, https:\/\/www.jumoon.top\/wp-content\/uploads\/2026\/06\/04\u5355\u4e2a\u6062\u590d.png 1205w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"515\" src=\"https:\/\/www.jumoon.top\/wp-content\/uploads\/2026\/06\/05\u6279\u91cf\u6062\u590d-1024x515.png\" alt=\"\" class=\"wp-image-1719\" srcset=\"https:\/\/www.jumoon.top\/wp-content\/uploads\/2026\/06\/05\u6279\u91cf\u6062\u590d-1024x515.png 1024w, https:\/\/www.jumoon.top\/wp-content\/uploads\/2026\/06\/05\u6279\u91cf\u6062\u590d-300x151.png 300w, https:\/\/www.jumoon.top\/wp-content\/uploads\/2026\/06\/05\u6279\u91cf\u6062\u590d-768x386.png 768w, https:\/\/www.jumoon.top\/wp-content\/uploads\/2026\/06\/05\u6279\u91cf\u6062\u590d.png 1287w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"has-text-align-center\">\u5177\u4f53\u811a\u672c\u4ee3\u7801\u5982\u4e0b\uff0c\u53ef\u4ee5\u4fdd\u5b58\u6210 xxx.sh,\u6bd4\u5982docker.sh,\u901a\u8fc7\u547d\u4ee4 bash .\/docker.sh \u6267\u884c\uff0c\u9700\u8981root\u6743\u9650\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/bin\/bash\n# =============================================\n# Docker \u955c\u50cf\u5907\u4efd\/\u6062\u590d\u7ba1\u7406\u811a\u672c\n# \u4f5c\u8005\uff1a\u5fc3\u82e5\u968f\u98ce\n# =============================================\n\n# \u6743\u9650\u68c0\u67e5\nif &#91; \"$(id -u)\" -ne 0 ]; then\n    echo -e \"\\033&#91;31m\u9519\u8bef\uff1a\u5fc5\u987b\u4f7f\u7528 root \u6743\u9650\u8fd0\u884c\u6b64\u811a\u672c\uff01\\033&#91;0m\"\n    exit 1\nfi\n\n# \u6837\u5f0f\nRED='\\033&#91;0;31m'; GREEN='\\033&#91;0;32m'; YELLOW='\\033&#91;1;33m'\nBLUE='\\033&#91;0;34m'; CYAN='\\033&#91;38;5;51m'; NC='\\033&#91;0m'\nCHECKMARK=\"\u2705\"; CROSS=\"\u274c\"; PROCESS=\"\u2699\ufe0f\"; INFO='\\033&#91;0;36m'\n\n# \u5168\u5c40\u53d8\u91cf\nfound_projects=()\nPAGE_SIZE=0\nBASE_PATH=\"\"\nIMAGE_BAK_DIR=\"$(pwd)\/Image_Bak\"\n\n# \u5de5\u5177\u51fd\u6570\nensure_dir_exists() { &#91; ! -d \"$1\" ] &amp;&amp; mkdir -p \"$1\"; }\nget_auto_page_size() {\n    local lines=$(tput lines 2>\/dev\/null || echo 24)\n    PAGE_SIZE=$((lines-16))\n    ((PAGE_SIZE&lt;5)) &amp;&amp; PAGE_SIZE=5\n    ((PAGE_SIZE>20)) &amp;&amp; PAGE_SIZE=20\n}\nprint_title() {\n    clear\n    echo -e \"${CYAN}=====================================================${NC}\"\n    echo -e \"${CYAN}        Docker \u955c\u50cf\u5907\u4efd\/\u6062\u590d\u7ba1\u7406\u811a\u672c by \u5fc3\u82e5\u968f\u98ce        ${NC}\"\n    echo -e \"${CYAN}=====================================================${NC}\\n\"\n}\n\n# \u626b\u63cf Docker \u9879\u76ee\nscan_projects() {\n    found_projects=()\n    echo -e \"${BLUE}\ud83d\udd0d \u6b63\u5728\u626b\u63cf &#91;$BASE_PATH] \u4e0b\u7684 Docker Compose \u9879\u76ee...${NC}\"\n    while IFS= read -r -d '' dir; do\n        if &#91; -f \"$dir\/docker-compose.yml\" ] || &#91; -f \"$dir\/docker-compose.yaml\" ]; then\n            found_projects+=(\"$dir\")\n        fi\n    done &lt; &lt;(find \"$BASE_PATH\" -maxdepth 2 -type d -print0 2>\/dev\/null)\n    &#91; ${#found_projects&#91;@]} -eq 0 ] &amp;&amp; { echo -e \"${RED}${CROSS} \u672a\u627e\u5230 Docker Compose \u9879\u76ee\uff01${NC}\"; exit 1; }\n}\n\n# \u83b7\u53d6\u9879\u76ee\u955c\u50cf\nget_images_from_compose() {\n    local dir=\"$1\"\n    local compose_file=\"$dir\/docker-compose.yml\"\n    &#91; ! -f \"$compose_file\" ] &amp;&amp; compose_file=\"$dir\/docker-compose.yaml\"\n    docker compose -f \"$compose_file\" config 2>\/dev\/null | awk '\/image:\/ {print $2}'\n}\n\n# ======================== \u5907\u4efd ========================\n# \u5168\u90e8\u672c\u5730\u955c\u50cf\nbackup_all_images() {\n    ensure_dir_exists \"$IMAGE_BAK_DIR\"\n    echo -e \"\\n${BLUE}\u5f00\u59cb\u5907\u4efd\u6240\u6709\u672c\u5730\u955c\u50cf...${NC}\"\n\n    mapfile -t all_images &lt; &lt;(docker image ls --format \"{{.Repository}}:{{.Tag}}\" | sort -u)\n\n    if &#91; ${#all_images&#91;@]} -eq 0 ]; then\n        echo -e \"${YELLOW}\u26a0\ufe0f \u5f53\u524d\u6ca1\u6709\u672c\u5730\u955c\u50cf\uff0c\u65e0\u6cd5\u5907\u4efd${NC}\"\n        read -p \"\u6309\u4efb\u610f\u952e\u8fd4\u56de\u4e3b\u83dc\u5355...\"\n        return\n    fi\n\n    for img in \"${all_images&#91;@]}\"; do\n        &#91; \"$img\" = \"&lt;none>:&lt;none>\" ] &amp;&amp; continue\n        safe_name=$(echo \"$img\" | tr '\/:' '__')\n        tar_file=\"$IMAGE_BAK_DIR\/${safe_name}.tar\"\n        &#91; -f \"$tar_file\" ] &amp;&amp; rm -f \"$tar_file\"\n        echo -e \"${PROCESS} \u5907\u4efd\u955c\u50cf: ${YELLOW}$img${NC}\"\n        docker save -o \"$tar_file\" \"$img\" &amp;&amp; echo -e \"${GREEN}${CHECKMARK} \u5df2\u4fdd\u5b58: $tar_file${NC}\" || echo -e \"${RED}${CROSS} \u4fdd\u5b58\u5931\u8d25: $img${NC}\"\n    done\n    read -p \"\u6309\u4efb\u610f\u952e\u8fd4\u56de\u4e3b\u83dc\u5355...\"\n}\n\n# \u5355\u4e2a\u955c\u50cf\nbackup_single_image() {\n    ensure_dir_exists \"$IMAGE_BAK_DIR\"\n    mapfile -t all_images &lt; &lt;(docker image ls --format \"{{.Repository}}:{{.Tag}}\" | sort -u)\n    if &#91; ${#all_images&#91;@]} -eq 0 ]; then\n        echo -e \"${YELLOW}\u26a0\ufe0f \u5f53\u524d\u6ca1\u6709\u672c\u5730\u955c\u50cf\u53ef\u5907\u4efd${NC}\"\n        read -p \"\u6309\u4efb\u610f\u952e\u8fd4\u56de\u4e3b\u83dc\u5355...\"\n        return\n    fi\n\n    echo -e \"\\n${BLUE}\u5f53\u524d\u6240\u6709\u672c\u5730\u955c\u50cf\uff1a${NC}\"\n    local idx=1\n    for img in \"${all_images&#91;@]}\"; do\n        echo \"  $idx) $img\"\n        ((idx++))\n    done\n\n    read -p \"\u8bf7\u9009\u62e9\u955c\u50cf\u7f16\u53f7: \" num\n    img=\"${all_images&#91;$((num-1))]}\"\n    &#91; -z \"$img\" ] &amp;&amp; { echo -e \"${RED}${CROSS} \u65e0\u6548\u9009\u62e9${NC}\"; read -p \"\u6309\u4efb\u610f\u952e\u8fd4\u56de\u4e3b\u83dc\u5355...\"; return; }\n    safe_name=$(echo \"$img\" | tr '\/:' '__')\n    tar_file=\"$IMAGE_BAK_DIR\/${safe_name}.tar\"\n    &#91; -f \"$tar_file\" ] &amp;&amp; rm -f \"$tar_file\"\n    docker save -o \"$tar_file\" \"$img\" &amp;&amp; echo -e \"${GREEN}${CHECKMARK} \u5907\u4efd\u6210\u529f: $tar_file${NC}\" || echo -e \"${RED}${CROSS} \u5907\u4efd\u5931\u8d25: $img${NC}\"\n    read -p \"\u6309\u4efb\u610f\u952e\u8fd4\u56de\u4e3b\u83dc\u5355...\"\n}\n\n# ======================== \u5bfc\u5165\u955c\u50cf ========================\nimport_images() {\n    local dir=\"$1\"\n    mapfile -t images &lt; &lt;(get_images_from_compose \"$dir\")\n    &#91; ${#images&#91;@]} -eq 0 ] &amp;&amp; return\n\n    for img in \"${images&#91;@]}\"; do\n        safe_name=$(echo \"$img\" | tr '\/:' '__')\n        tar_file=\"$IMAGE_BAK_DIR\/${safe_name}.tar\"\n        local_exist=0; bak_exist=0\n        docker image inspect \"$img\" >\/dev\/null 2>&amp;1 &amp;&amp; local_exist=1\n        &#91; -f \"$tar_file\" ] &amp;&amp; bak_exist=1\n\n        echo \"\"\n        echo \"================================================\"\n        echo \"\u955c\u50cf: $img\"\n        echo \"================================================\"\n\n        if &#91; $local_exist -eq 1 ] &amp;&amp; &#91; $bak_exist -eq 1 ]; then\n            echo \"1) \u4f7f\u7528\u5bb9\u5668\u5185\u955c\u50cf\"\n            echo \"2) \u4ece\u5907\u4efd\u5bfc\u5165\"\n            echo \"3) \u5728\u7ebf\u62c9\u53d6\u6700\u65b0\u955c\u50cf\"\n            read -p \"\u8bf7\u9009\u62e9 &#91;1]: \" choice\n            choice=${choice:-1}\n            case $choice in\n                2) docker load -i \"$tar_file\" ;;\n                3) docker pull \"$img\" ;;\n                *) echo \"\u4f7f\u7528\u5bb9\u5668\u5185\u955c\u50cf\" ;;\n            esac\n        elif &#91; $local_exist -eq 1 ]; then\n            echo \"1) \u4f7f\u7528\u5bb9\u5668\u5185\u955c\u50cf\"\n            echo \"2) \u5728\u7ebf\u62c9\u53d6\u6700\u65b0\u955c\u50cf\"\n            read -p \"\u8bf7\u9009\u62e9 &#91;1]: \" choice\n            choice=${choice:-1}\n            &#91;&#91; \"$choice\" == \"2\" ]] &amp;&amp; docker pull \"$img\"\n        elif &#91; $bak_exist -eq 1 ]; then\n            echo \"1) \u4ece\u5907\u4efd\u5bfc\u5165\"\n            echo \"2) \u5728\u7ebf\u62c9\u53d6\u6700\u65b0\u955c\u50cf\"\n            read -p \"\u8bf7\u9009\u62e9 &#91;1]: \" choice\n            choice=${choice:-1}\n            &#91;&#91; \"$choice\" == \"1\" ]] &amp;&amp; docker load -i \"$tar_file\"\n            &#91;&#91; \"$choice\" == \"2\" ]] &amp;&amp; docker pull \"$img\"\n        else\n            echo \"\u672c\u5730\u955c\u50cf\u548c\u5907\u4efd\u5747\u4e0d\u5b58\u5728\uff0c\u5f00\u59cb\u5728\u7ebf\u62c9\u53d6...\"\n            docker pull \"$img\"\n        fi\n    done\n}\n\n# ======================== \u5355\u4e2a\u9879\u76ee\u6062\u590d ========================\nrestore_single_project() {\n    local dir=\"$1\"\n    local project_name=$(basename \"$dir\")\n    echo -e \"\\n${PROCESS} \u5f00\u59cb\u6062\u590d\u9879\u76ee\uff1a${YELLOW}$project_name${NC}\"\n    import_images \"$dir\"\n    cd \"$dir\" || { echo -e \"${RED}${CROSS} \u65e0\u6cd5\u8fdb\u5165\u9879\u76ee\u76ee\u5f55 &#91;$dir]${NC}\"; return; }\n    docker compose up -d\n    &#91; $? -eq 0 ] &amp;&amp; echo -e \"${GREEN}${CHECKMARK} \u9879\u76ee &#91;$project_name] \u6062\u590d\u5b8c\u6210${NC}\" || echo -e \"${RED}${CROSS} \u6062\u590d\u5931\u8d25 &#91;$project_name]${NC}\"\n    cd - >\/dev\/null\n}\n\n# ======================== \u6279\u91cf\u6062\u590d ========================\nrestore_all_projects() {\n\n    # ==============================\n    # \u5217\u51fa\u5373\u5c06\u6062\u590d\u7684\u9879\u76ee\n    # ==============================\n    echo \"\"\n    echo -e \"${RED}\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550${NC}\"\n    echo -e \"${RED}        \u5373\u5c06\u6062\u590d\u4ee5\u4e0b\u9879\u76ee${NC}\"\n    echo -e \"${RED}\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550${NC}\"\n\n    local idx=1\n    for dir in \"${found_projects&#91;@]}\"; do\n        echo \" $idx) $(basename \"$dir\")\"\n        ((idx++))\n    done\n\n    echo \"\"\n    echo -e \"${YELLOW}\u5171 ${#found_projects&#91;@]} \u4e2a\u9879\u76ee${NC}\"\n    echo \"\"\n\n    # ==============================\n    # \u4e8c\u6b21\u786e\u8ba4\n    # ==============================\n    read -p \"\u8bf7\u8f93\u5165 YES \u786e\u8ba4\u6062\u590d\u5168\u90e8\u9879\u76ee\uff1a \" confirm\n    if &#91; \"$confirm\" != \"YES\" ]; then\n        echo -e \"${YELLOW}\u5df2\u53d6\u6d88\u64cd\u4f5c\u3002${NC}\"\n        read -p \"\u6309\u4efb\u610f\u952e\u8fd4\u56de\u4e3b\u83dc\u5355...\"\n        return\n    fi\n\n    # ==============================\n    # \u6279\u91cf\u6062\u590d\u903b\u8f91\n    # ==============================\n    for dir in \"${found_projects&#91;@]}\"; do\n        local images=($(get_images_from_compose \"$dir\"))\n        &#91; ${#images&#91;@]} -eq 0 ] &amp;&amp; continue\n\n        for img in \"${images&#91;@]}\"; do\n            safe_name=$(echo \"$img\" | tr '\/:' '__')\n            tar_file=\"$IMAGE_BAK_DIR\/${safe_name}.tar\"\n\n            if docker image inspect \"$img\" >\/dev\/null 2>&amp;1; then\n                echo -e \"${INFO} &#91;$img] \u5df2\u5b58\u5728\u672c\u5730\uff0c\u8df3\u8fc7\u5bfc\u5165${NC}\"\n            elif &#91; -f \"$tar_file\" ]; then\n                docker load -i \"$tar_file\" &amp;&amp; echo -e \"${GREEN}${CHECKMARK} \u5df2\u4ece\u5907\u4efd\u5bfc\u5165 &#91;$img]${NC}\" || echo -e \"${RED}${CROSS} \u5bfc\u5165\u5931\u8d25 &#91;$img]${NC}\"\n            else\n                echo -e \"${YELLOW}\u672a\u627e\u5230\u672c\u5730\u5907\u4efd\uff0c\u5728\u7ebf\u62c9\u53d6 &#91;$img]${NC}\"\n                docker pull \"$img\" &amp;&amp; echo -e \"${GREEN}${CHECKMARK} \u5728\u7ebf\u62c9\u53d6\u6210\u529f &#91;$img]${NC}\" || echo -e \"${RED}${CROSS} \u62c9\u53d6\u5931\u8d25 &#91;$img]${NC}\"\n            fi\n        done\n\n        cd \"$dir\" || continue\n        docker compose up -d --force-recreate\n        cd - >\/dev\/null\n    done\n\n    echo -e \"\\n${GREEN}${CHECKMARK} \u5168\u90e8\u9879\u76ee\u6062\u590d\u5b8c\u6210${NC}\"\n    read -p \"\u6309\u4efb\u610f\u952e\u8fd4\u56de\u4e3b\u83dc\u5355...\"\n}\n# ======================== \u83dc\u5355\u5206\u9875\u6d4f\u89c8 ========================\nmenu_list_and_restore_single() {\n    get_auto_page_size\n    local total_projects=${#found_projects&#91;@]}\n    local total_pages=$(( (total_projects + PAGE_SIZE - 1) \/ PAGE_SIZE ))\n    local current_page=1\n    local selected_idx=\"\"\n    while &#91; $current_page -le $total_pages ]; do\n        local start_idx=$(( (current_page-1) * PAGE_SIZE ))\n        local end_idx=$(( start_idx + PAGE_SIZE - 1 ))\n        &#91; $end_idx -ge $total_projects ] &amp;&amp; end_idx=$(( total_projects-1 ))\n        echo -e \"\\n${CYAN}========== \u7b2c $current_page\/$total_pages \u9875 ==========${NC}\"\n        for ((i=start_idx; i&lt;=end_idx; i++)); do\n            echo -e \"  ${GREEN}$((i+1)))${NC} $(basename \"${found_projects&#91;$i]}\")\"\n        done\n        echo -e \"${BLUE}-----------------------------------------------------${NC}\"\n        if &#91; $current_page -eq $total_pages ]; then\n            echo -ne \"${YELLOW}\u8f93\u5165\u9879\u76ee\u7f16\u53f7\u6062\u590d\uff080 \u8fd4\u56de\u4e3b\u83dc\u5355\uff09\uff0c\u6309\u56de\u8f66\u7ffb\u9875\uff1a${NC}\"\n        else\n            echo -ne \"${YELLOW}\u8f93\u5165\u9879\u76ee\u7f16\u53f7\u6062\u590d\uff0c\u6309\u56de\u8f66\u7ffb\u4e0b\u4e00\u9875\uff1a${NC}\"\n        fi\n        read user_input\n        if &#91; -z \"$user_input\" ]; then\n            if &#91; $current_page -eq $total_pages ]; then break; else current_page=$((current_page+1)); clear; fi\n        else\n            if ! &#91;&#91; \"$user_input\" =~ ^&#91;0-9]+$ ]]; then\n                echo -e \"${RED}${CROSS} \u8f93\u5165\u65e0\u6548\uff01${NC}\"; read -p \"\u6309\u4efb\u610f\u952e\u7ee7\u7eed...\"; clear; continue\n            fi\n            if &#91; \"$user_input\" -eq 0 ] &amp;&amp; &#91; $current_page -eq $total_pages ]; then\n                selected_idx=\"0\"; break\n            elif &#91; \"$user_input\" -ge 1 ] &amp;&amp; &#91; \"$user_input\" -le \"$total_projects\" ]; then\n                selected_idx=\"$user_input\"; break\n            else\n                echo -e \"${RED}${CROSS} \u7f16\u53f7\u65e0\u6548\uff01${NC}\"; read -p \"\u6309\u4efb\u610f\u952e\u7ee7\u7eed...\"; clear; continue\n            fi\n        fi\n    done\n    if &#91; \"$selected_idx\" = \"0\" ]; then return\n    elif &#91; -n \"$selected_idx\" ]; then\n        restore_single_project \"${found_projects&#91;$((selected_idx-1))]}\"\n        read -p \"\u6309\u4efb\u610f\u952e\u8fd4\u56de\u4e3b\u83dc\u5355...\"\n    else\n        echo -e \"${YELLOW}\u672a\u9009\u62e9\u4efb\u4f55\u9879\u76ee\uff0c\u8fd4\u56de\u4e3b\u83dc\u5355...${NC}\"; read -p \"\u6309\u4efb\u610f\u952e\u7ee7\u7eed...\"\n    fi\n}\n\n# ======================== \u4e3b\u83dc\u5355 ========================\nmain_menu() {\n    while true; do\n        print_title\n        echo -e \"${YELLOW}\ud83d\udd27 \u4e3b\u83dc\u5355${NC}\"\n        echo -e \"${BLUE}-----------------------------------------------------${NC}\"\n        echo -e \"  1) \u5907\u4efd\u6240\u6709\u672c\u5730\u955c\u50cf\"\n        echo -e \n        echo -e \"  2) \u5907\u4efd\u5355\u4e2a\u672c\u5730\u955c\u50cf\"\n        echo -e \n        echo -e \"  3) \u6062\u590d\u5355\u4e2a\u9879\u76ee\uff08\u4f1a\u641c\u7d22\u9879\u76ee\u6587\u4ef6\u5939\u4e2d\u7684\u9879\u76ee\uff0c\u8f93\u5165\u6570\u503c\u6062\u590d\uff09\"\n        echo -e \n        echo -e \"  4) \u6062\u590d\u5168\u90e8\u9879\u76ee\uff08\u4f1a\u6062\u590d\u9879\u76ee\u6587\u4ef6\u5939\u4e0b\u6bcf\u4e2a\u9879\u76ee\uff0c\u614e\u7528\uff01\uff01\uff09\"\n        echo -e \n        echo -e \"  0) \u9000\u51fa\"\n        echo -e \"${BLUE}-----------------------------------------------------${NC}\"\n        echo -ne \"${YELLOW}\u8bf7\u9009\u62e9\u64cd\u4f5c\uff080-4\uff09\uff1a${NC}\"\n        read choice\n        echo \"\"\n        case $choice in\n            1) backup_all_images ;;\n            2) backup_single_image ;;\n            3) menu_list_and_restore_single ;;\n            4) restore_all_projects ;;\n            0) echo -e \"${GREEN}\ud83d\udc4b \u611f\u8c22\u4f7f\u7528\uff01${NC}\"; exit 0 ;;\n            *) echo -e \"${RED}${CROSS} \u65e0\u6548\u9009\u62e9\uff01\u8bf7\u8f93\u5165 0-4 \u4e4b\u95f4\u7684\u6570\u5b57${NC}\"; read -p \"\u6309\u4efb\u610f\u952e\u8fd4\u56de\u4e3b\u83dc\u5355...\" ;;\n        esac\n    done\n}\n\n# \u4e3b\u5165\u53e3\nmain() {\n    print_title\n    echo -ne \"${YELLOW}\u8bf7\u8f93\u5165 Docker \u9879\u76ee\u76ee\u5f55\u8def\u5f84\uff08\u4f8b\u5982\uff1a\/vol1\/1000\/000.Docker\uff09:\\n> ${NC}\"\n    read BASE_PATH\n    &#91; -z \"$BASE_PATH\" ] || &#91; ! -d \"$BASE_PATH\" ] &amp;&amp; { echo -e \"${RED}${CROSS} \u8def\u5f84\u65e0\u6548\uff01${NC}\"; exit 1; }\n    ensure_dir_exists \"$IMAGE_BAK_DIR\"\n    scan_projects\n    main_menu\n}\n\nmain<\/code><\/pre>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u5e74\u521d\u7684\u65f6\u5019\u505a\u4e86\u4e2a \u98de\u725bNAS Docker \u5bb9\u5668\u955c\u50cf\u5907\u4efd \u7684\u811a\u672c\uff0c\u5b9e\u9645\u4f7f\u7528\u4e2d\u6709\u4e9b\u4e0d\u65b9\u4fbf\u7684\uff0c\u505a\u4e86\u70b9\u5347\u7ea7\uff0c\u5b9e\u73b0\u6307\u5b9a [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"site-container-style":"default","site-container-layout":"default","site-sidebar-layout":"default","site-transparent-header":"default","disable-article-header":"default","disable-site-header":"default","disable-site-footer":"default","disable-content-area-spacing":"default","footnotes":""},"categories":[19],"tags":[],"class_list":["post-1714","post","type-post","status-publish","format-standard","hentry","category-19"],"_links":{"self":[{"href":"https:\/\/www.jumoon.top\/index.php?rest_route=\/wp\/v2\/posts\/1714","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.jumoon.top\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.jumoon.top\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.jumoon.top\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.jumoon.top\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1714"}],"version-history":[{"count":1,"href":"https:\/\/www.jumoon.top\/index.php?rest_route=\/wp\/v2\/posts\/1714\/revisions"}],"predecessor-version":[{"id":1720,"href":"https:\/\/www.jumoon.top\/index.php?rest_route=\/wp\/v2\/posts\/1714\/revisions\/1720"}],"wp:attachment":[{"href":"https:\/\/www.jumoon.top\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1714"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.jumoon.top\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1714"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.jumoon.top\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1714"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}