From 89f24a7fefee76ac8f48eb69489da9723b1c4607 Mon Sep 17 00:00:00 2001 From: Wang Defa Date: Fri, 26 Dec 2025 15:20:51 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=89=80=E6=9C=89?= =?UTF-8?q?=E8=84=9A=E6=9C=AC=E7=9A=84=20process=20substitution=20?= =?UTF-8?q?=E5=85=BC=E5=AE=B9=E6=80=A7=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 问题描述 在使用 `set -u` 严格模式时,`source <(curl ...)` 或 `source <(wget ...)` 的 process substitution 方式会在脚本退出时产生错误: ``` /dev/fd/63: line 1: fifo: unbound variable ``` ## 根本原因 Process substitution 创建的临时文件描述符(如 /dev/fd/63)在退出时 与 Bash 的 `set -u` 严格模式存在兼容性问题,导致错误消息。 ## 修复方案 将 process substitution 替换为临时文件方案: **旧方案(有问题):** ```bash source <(curl -fsSL "$url") ``` **新方案(兼容性好):** ```bash temp_loader=$(mktemp) curl -fsSL "$url" -o "$temp_loader" source "$temp_loader" rm -f "$temp_loader" ``` ## 修改的文件 批量修复了所有 7 个脚本的远程加载逻辑: - oci/create_instance.sh - linux/create_raid0_array.sh - linux/install_oh_my_zsh.sh - linux/repartition_disks.sh - gcp/create_ai_projects.sh - gcp/delete_all_projects.sh - common/demo_usage.sh ## 优势 - ✅ 避免 process substitution 的兼容性问题 - ✅ 与 `set -u` 严格模式完全兼容 - ✅ 显式的临时文件管理,更易理解 - ✅ 确保所有分支都正确清理临时文件 - ✅ 保持 curl/wget 双重支持不变 --- common/demo_usage.sh | 23 +++++++++++++++++------ gcp/create_ai_projects.sh | 23 +++++++++++++++++------ gcp/delete_all_projects.sh | 23 +++++++++++++++++------ linux/create_raid0_array.sh | 23 +++++++++++++++++------ linux/install_oh_my_zsh.sh | 23 +++++++++++++++++------ linux/repartition_disks.sh | 23 +++++++++++++++++------ oci/create_instance.sh | 23 +++++++++++++++++------ 7 files changed, 119 insertions(+), 42 deletions(-) diff --git a/common/demo_usage.sh b/common/demo_usage.sh index 95e82a2..672275e 100755 --- a/common/demo_usage.sh +++ b/common/demo_usage.sh @@ -48,20 +48,31 @@ load_common_libs() { # 使用远程库 if [[ "$use_remote" == "true" ]]; then + # 下载到临时文件(避免 process substitution 与 set -u 的交互问题) + local temp_loader + temp_loader=$(mktemp) + if command -v curl &>/dev/null; then echo "[INFO] 使用 curl 下载远程库..." >&2 - # shellcheck disable=SC1090 - if source <(curl -fsSL "${REMOTE_BASE_URL}/common/remote_loader.sh" 2>/dev/null); then - return 0 + if curl -fsSL "${REMOTE_BASE_URL}/common/remote_loader.sh" -o "$temp_loader" 2>/dev/null; then + # shellcheck disable=SC1090 + if source "$temp_loader"; then + rm -f "$temp_loader" + return 0 + fi fi elif command -v wget &>/dev/null; then echo "[INFO] 使用 wget 下载远程库..." >&2 - # shellcheck disable=SC1090 - if source <(wget -qO- "${REMOTE_BASE_URL}/common/remote_loader.sh" 2>/dev/null); then - return 0 + if wget -qO "$temp_loader" "${REMOTE_BASE_URL}/common/remote_loader.sh" 2>/dev/null; then + # shellcheck disable=SC1090 + if source "$temp_loader"; then + rm -f "$temp_loader" + return 0 + fi fi fi + rm -f "$temp_loader" echo "[ERROR] 无法加载公共库" >&2 echo "[ERROR] - 本地库不存在" >&2 echo "[ERROR] - 远程下载失败(需要 curl 或 wget)" >&2 diff --git a/gcp/create_ai_projects.sh b/gcp/create_ai_projects.sh index a2f278e..101d4cd 100644 --- a/gcp/create_ai_projects.sh +++ b/gcp/create_ai_projects.sh @@ -48,20 +48,31 @@ load_common_libs() { # 使用远程库 if [[ "$use_remote" == "true" ]]; then + # 下载到临时文件(避免 process substitution 与 set -u 的交互问题) + local temp_loader + temp_loader=$(mktemp) + if command -v curl &>/dev/null; then echo "[INFO] 使用 curl 下载远程库..." >&2 - # shellcheck disable=SC1090 - if source <(curl -fsSL "${REMOTE_BASE_URL}/common/remote_loader.sh" 2>/dev/null); then - return 0 + if curl -fsSL "${REMOTE_BASE_URL}/common/remote_loader.sh" -o "$temp_loader" 2>/dev/null; then + # shellcheck disable=SC1090 + if source "$temp_loader"; then + rm -f "$temp_loader" + return 0 + fi fi elif command -v wget &>/dev/null; then echo "[INFO] 使用 wget 下载远程库..." >&2 - # shellcheck disable=SC1090 - if source <(wget -qO- "${REMOTE_BASE_URL}/common/remote_loader.sh" 2>/dev/null); then - return 0 + if wget -qO "$temp_loader" "${REMOTE_BASE_URL}/common/remote_loader.sh" 2>/dev/null; then + # shellcheck disable=SC1090 + if source "$temp_loader"; then + rm -f "$temp_loader" + return 0 + fi fi fi + rm -f "$temp_loader" echo "[ERROR] 无法加载公共库" >&2 echo "[ERROR] - 本地库不存在" >&2 echo "[ERROR] - 远程下载失败(需要 curl 或 wget)" >&2 diff --git a/gcp/delete_all_projects.sh b/gcp/delete_all_projects.sh index 4c6214f..dc77322 100644 --- a/gcp/delete_all_projects.sh +++ b/gcp/delete_all_projects.sh @@ -49,20 +49,31 @@ load_common_libs() { # 使用远程库 if [[ "$use_remote" == "true" ]]; then + # 下载到临时文件(避免 process substitution 与 set -u 的交互问题) + local temp_loader + temp_loader=$(mktemp) + if command -v curl &>/dev/null; then echo "[INFO] 使用 curl 下载远程库..." >&2 - # shellcheck disable=SC1090 - if source <(curl -fsSL "${REMOTE_BASE_URL}/common/remote_loader.sh" 2>/dev/null); then - return 0 + if curl -fsSL "${REMOTE_BASE_URL}/common/remote_loader.sh" -o "$temp_loader" 2>/dev/null; then + # shellcheck disable=SC1090 + if source "$temp_loader"; then + rm -f "$temp_loader" + return 0 + fi fi elif command -v wget &>/dev/null; then echo "[INFO] 使用 wget 下载远程库..." >&2 - # shellcheck disable=SC1090 - if source <(wget -qO- "${REMOTE_BASE_URL}/common/remote_loader.sh" 2>/dev/null); then - return 0 + if wget -qO "$temp_loader" "${REMOTE_BASE_URL}/common/remote_loader.sh" 2>/dev/null; then + # shellcheck disable=SC1090 + if source "$temp_loader"; then + rm -f "$temp_loader" + return 0 + fi fi fi + rm -f "$temp_loader" echo "[ERROR] 无法加载公共库" >&2 echo "[ERROR] - 本地库不存在" >&2 echo "[ERROR] - 远程下载失败(需要 curl 或 wget)" >&2 diff --git a/linux/create_raid0_array.sh b/linux/create_raid0_array.sh index 195622a..0224570 100755 --- a/linux/create_raid0_array.sh +++ b/linux/create_raid0_array.sh @@ -49,20 +49,31 @@ load_common_libs() { # 使用远程库 if [[ "$use_remote" == "true" ]]; then + # 下载到临时文件(避免 process substitution 与 set -u 的交互问题) + local temp_loader + temp_loader=$(mktemp) + if command -v curl &>/dev/null; then echo "[INFO] 使用 curl 下载远程库..." >&2 - # shellcheck disable=SC1090 - if source <(curl -fsSL "${REMOTE_BASE_URL}/common/remote_loader.sh" 2>/dev/null); then - return 0 + if curl -fsSL "${REMOTE_BASE_URL}/common/remote_loader.sh" -o "$temp_loader" 2>/dev/null; then + # shellcheck disable=SC1090 + if source "$temp_loader"; then + rm -f "$temp_loader" + return 0 + fi fi elif command -v wget &>/dev/null; then echo "[INFO] 使用 wget 下载远程库..." >&2 - # shellcheck disable=SC1090 - if source <(wget -qO- "${REMOTE_BASE_URL}/common/remote_loader.sh" 2>/dev/null); then - return 0 + if wget -qO "$temp_loader" "${REMOTE_BASE_URL}/common/remote_loader.sh" 2>/dev/null; then + # shellcheck disable=SC1090 + if source "$temp_loader"; then + rm -f "$temp_loader" + return 0 + fi fi fi + rm -f "$temp_loader" echo "[ERROR] 无法加载公共库" >&2 echo "[ERROR] - 本地库不存在" >&2 echo "[ERROR] - 远程下载失败(需要 curl 或 wget)" >&2 diff --git a/linux/install_oh_my_zsh.sh b/linux/install_oh_my_zsh.sh index fb6d60b..f5aa06a 100644 --- a/linux/install_oh_my_zsh.sh +++ b/linux/install_oh_my_zsh.sh @@ -48,20 +48,31 @@ load_common_libs() { # 使用远程库 if [[ "$use_remote" == "true" ]]; then + # 下载到临时文件(避免 process substitution 与 set -u 的交互问题) + local temp_loader + temp_loader=$(mktemp) + if command -v curl &>/dev/null; then echo "[INFO] 使用 curl 下载远程库..." >&2 - # shellcheck disable=SC1090 - if source <(curl -fsSL "${REMOTE_BASE_URL}/common/remote_loader.sh" 2>/dev/null); then - return 0 + if curl -fsSL "${REMOTE_BASE_URL}/common/remote_loader.sh" -o "$temp_loader" 2>/dev/null; then + # shellcheck disable=SC1090 + if source "$temp_loader"; then + rm -f "$temp_loader" + return 0 + fi fi elif command -v wget &>/dev/null; then echo "[INFO] 使用 wget 下载远程库..." >&2 - # shellcheck disable=SC1090 - if source <(wget -qO- "${REMOTE_BASE_URL}/common/remote_loader.sh" 2>/dev/null); then - return 0 + if wget -qO "$temp_loader" "${REMOTE_BASE_URL}/common/remote_loader.sh" 2>/dev/null; then + # shellcheck disable=SC1090 + if source "$temp_loader"; then + rm -f "$temp_loader" + return 0 + fi fi fi + rm -f "$temp_loader" echo "[ERROR] 无法加载公共库" >&2 echo "[ERROR] - 本地库不存在" >&2 echo "[ERROR] - 远程下载失败(需要 curl 或 wget)" >&2 diff --git a/linux/repartition_disks.sh b/linux/repartition_disks.sh index f024795..900df76 100644 --- a/linux/repartition_disks.sh +++ b/linux/repartition_disks.sh @@ -49,20 +49,31 @@ load_common_libs() { # 使用远程库 if [[ "$use_remote" == "true" ]]; then + # 下载到临时文件(避免 process substitution 与 set -u 的交互问题) + local temp_loader + temp_loader=$(mktemp) + if command -v curl &>/dev/null; then echo "[INFO] 使用 curl 下载远程库..." >&2 - # shellcheck disable=SC1090 - if source <(curl -fsSL "${REMOTE_BASE_URL}/common/remote_loader.sh" 2>/dev/null); then - return 0 + if curl -fsSL "${REMOTE_BASE_URL}/common/remote_loader.sh" -o "$temp_loader" 2>/dev/null; then + # shellcheck disable=SC1090 + if source "$temp_loader"; then + rm -f "$temp_loader" + return 0 + fi fi elif command -v wget &>/dev/null; then echo "[INFO] 使用 wget 下载远程库..." >&2 - # shellcheck disable=SC1090 - if source <(wget -qO- "${REMOTE_BASE_URL}/common/remote_loader.sh" 2>/dev/null); then - return 0 + if wget -qO "$temp_loader" "${REMOTE_BASE_URL}/common/remote_loader.sh" 2>/dev/null; then + # shellcheck disable=SC1090 + if source "$temp_loader"; then + rm -f "$temp_loader" + return 0 + fi fi fi + rm -f "$temp_loader" echo "[ERROR] 无法加载公共库" >&2 echo "[ERROR] - 本地库不存在" >&2 echo "[ERROR] - 远程下载失败(需要 curl 或 wget)" >&2 diff --git a/oci/create_instance.sh b/oci/create_instance.sh index b8e0462..33c6add 100644 --- a/oci/create_instance.sh +++ b/oci/create_instance.sh @@ -48,20 +48,31 @@ load_common_libs() { # 使用远程库 if [[ "$use_remote" == "true" ]]; then + # 下载到临时文件(避免 process substitution 与 set -u 的交互问题) + local temp_loader + temp_loader=$(mktemp) + if command -v curl &>/dev/null; then echo "[INFO] 使用 curl 下载远程库..." >&2 - # shellcheck disable=SC1090 - if source <(curl -fsSL "${REMOTE_BASE_URL}/common/remote_loader.sh" 2>/dev/null); then - return 0 + if curl -fsSL "${REMOTE_BASE_URL}/common/remote_loader.sh" -o "$temp_loader" 2>/dev/null; then + # shellcheck disable=SC1090 + if source "$temp_loader"; then + rm -f "$temp_loader" + return 0 + fi fi elif command -v wget &>/dev/null; then echo "[INFO] 使用 wget 下载远程库..." >&2 - # shellcheck disable=SC1090 - if source <(wget -qO- "${REMOTE_BASE_URL}/common/remote_loader.sh" 2>/dev/null); then - return 0 + if wget -qO "$temp_loader" "${REMOTE_BASE_URL}/common/remote_loader.sh" 2>/dev/null; then + # shellcheck disable=SC1090 + if source "$temp_loader"; then + rm -f "$temp_loader" + return 0 + fi fi fi + rm -f "$temp_loader" echo "[ERROR] 无法加载公共库" >&2 echo "[ERROR] - 本地库不存在" >&2 echo "[ERROR] - 远程下载失败(需要 curl 或 wget)" >&2