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

Bats测试中split_line函数数组赋值失败问题排查

split_line函数的数组传递问题分析

问题场景

需要实现split_line函数:将输入字符串分割为数组,当第二个参数不为1时移除数组首元素,返回可用于数组赋值的结果。但第三个测试用例失败,日志显示赋值后的数组仅包含一个完整字符串,而非预期的分割后元素。

原代码与失败日志

原函数与测试代码

#!/usr/bin/env bats

log_debug() {
    echo "$@" >> /dev/stderr
}

split_line() {
    rmfirst=${2:-0}
    log_debug "args: \"$1\", ${rmfirst}"
    read -ra out_arr <<< "$1"
    log_debug "out: $(declare -p out_arr)"
    if [ $rmfirst -ne 1 ] ; then
        unset "out_arr[0]"
    fi
    echo "${out_arr[@]}"
}


@test "split line" {
    line_arr=("$(split_line "GETINFO version")")
    [ "${line_arr[0]}" = "version" ]
}

@test "split line rmfirst" {
    line_arr=("$(split_line "GETINFO version" 0)")
    [ "${line_arr[0]}" = "version" ]
}

@test "split line no-rmfirst" {
    IFS=" " line_arr=("$(split_line "GETINFO version" 1)")
    [[ "$(declare -p line_arr)" == 'declare -'[aA]* ]]
    log_debug "$(declare -p line_arr)"
    [[ "${line_arr[0]}" == "GETINFO" ]]
    [[ ${#line_arr} -eq 2 ]]
    [[ "${line_arr[1]}" == "version" ]]
}

测试失败日志

✓ split line
 ✓ split line rmfirst
 ✗ split line no-rmfirst
   (in test file tests/foundational.bats, line 39)
     `[[ "${line_arr[0]}" == "GETINFO" ]]' failed
   args: "GETINFO version", 1
   out: declare -a out_arr=([0]="GETINFO" [1]="version")
   declare -a line_arr=([0]="GETINFO version")

3 tests, 1 failure

问题根源

  1. 数组输出方式错误:
    函数最后用echo "${out_arr[@]}"输出数组,会将所有元素用空格拼接成单个字符串。这种方式无法保留数组的结构,当捕获输出并赋值时,无法直接还原为多元素数组。

  2. 测试赋值方式错误:
    测试中line_arr=("$(split_line ...)")的写法,会把命令输出的整个内容当作数组的单个元素——因为引号的存在,即使设置了IFS=" ",Bash也不会分割这个字符串,导致line_arr只有一个元素"GETINFO version"。

  3. 数组索引不连续(次要问题):
    当unset out_arr[0]后,数组的索引会变成不连续状态(比如原[1]元素的索引仍为1),虽然echo "${out_arr[@]}"能输出元素,但数组的长度计算和索引访问会有潜在问题。

修复方案

修复split_line函数

改用换行符分隔每个元素输出,这样能可靠保留数组的元素结构,避免空格拼接的歧义:

split_line() {
    rmfirst=${2:-0}
    log_debug "args: \"$1\", ${rmfirst}"
    read -ra out_arr <<< "$1"
    log_debug "out: $(declare -p out_arr)"
    if [ "$rmfirst" -ne 1 ]; then
        unset "out_arr[0]"
        # 重新索引数组,让索引从0开始连续
        out_arr=("${out_arr[@]}")
    fi
    # 每个元素单独一行输出,确保能被正确还原为数组
    printf '%s\n' "${out_arr[@]}"
}

修复测试用例

使用mapfile读取函数输出,直接将每行内容转为数组元素:

@test "split line no-rmfirst" {
    mapfile -t line_arr < <(split_line "GETINFO version" 1)
    [[ "$(declare -p line_arr)" == 'declare -'[aA]* ]]
    log_debug "$(declare -p line_arr)"
    [[ "${line_arr[0]}" == "GETINFO" ]]
    [[ ${#line_arr[@]} -eq 2 ]]
    [[ "${line_arr[1]}" == "version" ]]
}

另外,前两个测试也需要同步修改赋值方式,比如:

@test "split line" {
    mapfile -t line_arr < <(split_line "GETINFO version")
    [ "${line_arr[0]}" = "version" ]
}

@test "split line rmfirst" {
    mapfile -t line_arr < <(split_line "GETINFO version" 0)
    [ "${line_arr[0]}" = "version" ]
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 08:01:02