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

如何用原生Bash实现从YAML文件提取指定属性值的自定义函数

原有代码问题排查
  • 语法错误:变量赋值时等号两侧不能加空格,curr_line_prop = ${curr_line_props[0]} 会被bash识别为命令执行,直接报错
  • 匹配逻辑错误:通配符匹配不能用单中括号[]的test表达式,必须用双中括号[[]]才支持
  • 缺失YAML缩进处理:完全没有判断字段的层级,会把不同父节点下的同名字段混淆,比如多个AppNode下的Name字段会被误匹配
  • 返回值逻辑错误:bash的return只能返回0-255的状态码,不能返回字符串结果,正确的返回方式是用echo输出结果,调用时通过命令替换$()接收
  • 没有处理值的格式:读取到的属性值会携带多余的前置空格、引号,没有做清洗
  • 名称匹配逻辑未实现:代码中只预留了数字索引的处理分支,用属性值匹配(比如[$DomainName])的逻辑完全为空,无法满足调用要求
纯Bash实现的getValue函数

不需要任何外部依赖,完全符合要求的调用规则,支持数字索引和名称匹配,适配你提供的YAML格式:

function getValue {
    local prop_path="$1"
    local yaml_file="$2"
    # 解析属性路径为层级数组
    IFS='_' read -r -a levels <<< "$prop_path"
    local level_count=${#levels[@]}
    local current_level=0
    local expected_indent=0
    local INDENT_STEP=2 # YAML每层级缩进为2空格,若你的文件是4空格可修改此值

    # 逐行读取YAML,兼容结尾无换行的情况
    while IFS= read -r line || [ -n "$line" ]; do
        # 跳过空行、注释行
        [[ $line =~ ^[[:space:]]*# ]] || [[ -z $line ]] && continue
        # 计算当前行缩进长度
        local indent_str=${line%%[^[:space:]]*}
        local indent=${#indent_str}
        # 提取键和值,清洗前后空格
        local line_content=${line#$indent_str}
        local key=${line_content%%:*}
        local value=${line_content#*:}
        value=$(echo "$value" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' -e 's/^["'\'']//' -e 's/["'\'']$//')

        # 缩进小于预期,说明已经退出当前匹配的父节点,回退层级
        if (( indent < expected_indent && current_level > 0 )); then
            ((current_level--))
            expected_indent=$((expected_indent - INDENT_STEP))
        fi
        # 层级已匹配完直接退出
        (( current_level >= level_count )) && break

        # 解析当前待匹配层级的键和索引
        local curr_spec=${levels[$current_level]}
        local curr_key=${curr_spec%%\[*}
        local curr_idx=""
        [[ $curr_spec =~ \[(.*)\] ]] && curr_idx=${BASH_REMATCH[1]}

        # 当前行键名不匹配,跳过
        [[ $key != "$curr_key" ]] && continue

        # 处理索引逻辑
        if [[ -n $curr_idx ]]; then
            # 数字索引:匹配第N个同层级同键节点
            if [[ $curr_idx =~ ^[0-9]+$ ]]; then
                local match_count=0
                local temp_line="$line"
                while true; do
                    ((match_count++))
                    if (( match_count == curr_idx )); then
                        ((current_level++))
                        expected_indent=$((indent + INDENT_STEP))
                        (( current_level == level_count )) && echo "$value" && return 0
                        break
                    fi
                    # 找下一个同层级同键节点
                    local found_next=0
                    while IFS= read -r next_line || [ -n "$next_line" ]; do
                        local next_indent_str=${next_line%%[^[:space:]]*}
                        local next_indent=${#next_indent_str}
                        if (( next_indent <= indent )); then
                            [[ $next_line =~ ^[[:space:]]*$curr_key: ]] && temp_line="$next_line" && found_next=1
                            break
                        fi
                    done
                    (( found_next == 0 )) && break
                    line="$temp_line"
                done
            # 名称匹配:匹配下Name等于指定值的同键节点
            else
                local found_match=0
                while true; do
                    # 查找当前节点下的Name字段
                    while IFS= read -r sub_line || [ -n "$sub_line" ]; do
                        local sub_indent_str=${sub_line%%[^[:space:]]*}
                        local sub_indent=${#sub_indent_str}
                        (( sub_indent <= indent )) && break
                        local sub_content=${sub_line#$sub_indent_str}
                        if [[ $sub_content == Name:* ]]; then
                            local name_val=${sub_content#*:}
                            name_val=$(echo "$name_val" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' -e 's/^["'\'']//' -e 's/["'\'']$//')
                            if [[ $name_val == "$curr_idx" ]]; then
                                found_match=1
                                break 2
                            fi
                            break
                        fi
                    done
                    # 没匹配到找下一个同层级同键节点
                    local found_next=0
                    while IFS= read -r next_line || [ -n "$next_line" ]; do
                        local next_indent_str=${next_line%%[^[:space:]]*}
                        local next_indent=${#next_indent_str}
                        if (( next_indent <= indent )); then
                            [[ $next_line =~ ^[[:space:]]*$curr_key: ]] && line="$next_line" && found_next=1
                            break
                        fi
                    done
                    (( found_next == 0 )) && break
                done
                if (( found_match == 1 )); then
                    ((current_level++))
                    expected_indent=$((indent + INDENT_STEP))
                    (( current_level == level_count )) && echo "$value" && return 0
                fi
            fi
        else
            # 无索引直接匹配
            ((current_level++))
            expected_indent=$((indent + INDENT_STEP))
            (( current_level == level_count )) && echo "$value" && return 0
        fi
    done < "$yaml_file"
    # 未匹配到返回空
    echo ""
    return 1
}
使用示例

调用时需要用bash的命令替换语法接收返回值:

# 替换为你的YAML文件实际路径
YAML_PATH="/path/my_yaml.yml"

DomainName=$(getValue "Domains_Domain[1]_Name" "$YAML_PATH")
AppSpaceName=$(getValue "Domains_Domain[$DomainName]_AppSpaces_AppSpace[1]_Name" "$YAML_PATH")
AppNodeName=$(getValue "Domains_Domain[$DomainName]_AppSpaces_AppSpace[$AppSpaceName]_AppNodes_AppNode[1]_Name" "$YAML_PATH")
AppName=$(getValue "Domains_Domain[$DomainName]_AppSpaces_AppSpace[$AppSpaceName]_AppNodes_AppNode[$AppNodeName]_Applications_Application[1]_Name" "$YAML_PATH")
AppVersion=$(getValue "Domains_Domain[$DomainName]_AppSpaces_AppSpace[$AppSpaceName]_AppNodes_AppNode[$AppNodeName]_Applications_Application[$AppName]_Version" "$YAML_PATH")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 10:06:03