You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在POSIX兼容的/bin/sh脚本中实现类似#ifdef的包含保护?

POSIX可移植的Shell脚本包含保护实现

原代码的核心问题

你提供的脚本之所以始终判定已被包含,是因为保护变量的检查逻辑错误:

if test "${guard}" ; then return ; fi

这里的${guard}是拼接出的变量名字符串(比如H_/path/to/script.sh转换后的合法变量名),test "${guard}"实际是判断这个字符串是否非空——显然它永远非空,所以无论脚本是否被包含过,都会直接执行return,导致核心代码从未运行。

正确的POSIX兼容实现思路

要实现类似C语言#pragma once的包含保护,需要三个核心步骤:

  1. 可靠获取当前脚本的绝对路径(确保不同调用方式下路径唯一)
  2. 基于绝对路径生成唯一的保护变量名
  3. 检查该变量是否已定义,若已定义则退出当前脚本执行,否则标记变量为已定义

完整实现代码

#!/bin/sh
set -eu

# POSIX兼容的绝对路径获取函数,处理符号链接
get_absolute_path() {
    local path="$1"
    # 解析符号链接
    while [ -L "$path" ]; do
        path=$(readlink "$path")
    done
    # 确保文件存在
    if [ ! -f "$path" ]; then
        echo "Error: Script file '$path' not found" >&2
        return 1
    fi
    # 拼接绝对路径
    local script_dir=$(cd "$(dirname "$path")" && pwd)
    local script_name=$(basename "$path")
    echo "${script_dir}/${script_name}"
}

# 获取当前脚本的绝对路径
this_file=$(get_absolute_path "$0")

# 生成唯一的保护变量名(替换非法字符为下划线)
guard="H_$(printf '%s' "$this_file" | sed 's/[^a-zA-Z0-9_]/_/g')"

# 包含保护逻辑:检查变量是否已定义,已定义则退出
if [ -n "${!guard:-}" ]; then
    return 0
fi
# 标记脚本已被加载(动态设置变量)
eval "${guard}=1"

# --------------------------
# 脚本核心内容开始
# --------------------------
DIR=$(dirname "$this_file")
export DIR

# 简化的脚本根目录获取(根据实际层级调整)
SCRIPT_ROOT_DIR="${SCRIPT_ROOT_DIR:-$(cd "$DIR/../../.." && pwd)}"
export SCRIPT_ROOT_DIR

# 引入其他脚本
. "${SCRIPT_ROOT_DIR}/_lib/_common/os_info.sh"

echo "执行脚本核心内容:$this_file"

关键细节说明

  1. 绝对路径可靠性:get_absolute_path函数处理符号链接,确保无论脚本是直接执行、通过source调用还是通过符号链接启动,都能得到唯一的绝对路径,避免同一个脚本因路径不同生成不同的保护变量。
  2. 间接变量引用:${!guard:-}是POSIX兼容的间接引用语法,用来检查名为$guard的变量是否已定义且非空——这才是正确的包含保护判断逻辑。
  3. 动态变量设置:用eval "${guard}=1"设置保护变量,因为guard是动态生成的变量名,直接赋值无法生效,eval能确保变量在当前shell上下文被正确定义。
  4. 避免不必要的export:包含保护只需要在当前shell上下文生效,无需导出到环境变量,减少环境变量污染。

内容的提问来源于stack exchange,提问作者Samuel Marks

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 07:16:14