首页 > 解决方案 > 复制时避免 bash 拆分字符串数组

问题描述

为了让我的脚本简单,我使用字符串变量作为变量名来恢复其他变量(在本例中为数组):

#!/usr/bin/env bash

ANDROID_BUILD_OPTIONS=("armeabi-v7a" "arm64-v8a")
ANDROID_BUILD_DESCRIPTIONS=("Regular ARM 32-bit" "Regular ARM 64-bit")
ANDROID_BUILD_OPTIONS_COUNT=2
IOS_BUILD_OPTIONS=("base")
IOS_BUILD_DESCRIPTIONS=("Basic xcode target (ignored on non-MacOS build)")
IOS_BUILD_OPTIONS_COUNT=1

# Initial print of the arrays
echo "- ANDROID_BUILD_DESCRIPTIONS -"
i=0
while [ $i -lt ${ANDROID_BUILD_OPTIONS_COUNT} ]; do
    echo "[$i] Name: ${ANDROID_BUILD_OPTIONS[i]}, description: ${ANDROID_BUILD_DESCRIPTIONS[i]}"
    i=$((i + 1))
done
echo "- IOS_BUILD_DESCRIPTIONS -"
i=0
while [ $i -lt ${IOS_BUILD_OPTIONS_COUNT} ]; do
    echo "[$i] Name: ${IOS_BUILD_OPTIONS[i]}, description: ${IOS_BUILD_DESCRIPTIONS[i]}"
    i=$((i + 1))
done
echo

for TARGET in ANDROID IOS; do
    varname="${TARGET}_BUILD_OPTIONS[@]"
    TARGET_BUILD_OPTIONS=${!varname}
    varname="${TARGET}_BUILD_DESCRIPTIONS[@]"
    TARGET_BUILD_DESCRIPTIONS=${!varname}
    varname="${TARGET}_BUILD_OPTIONS_COUNT"
    TARGET_BUILD_OPTIONS_COUNT=${!varname}

    echo "- TARGET_BUILD_DESCRIPTIONS (${TARGET}) -"
    i=0
    while [ $i -lt ${TARGET_BUILD_OPTIONS_COUNT} ]; do
        echo "[$i] Name: ${TARGET_BUILD_OPTIONS[i]}, description: ${TARGET_BUILD_DESCRIPTIONS[i]}"
        i=$((i + 1))
    done
done

上面的脚本产生以下输出:

- ANDROID_BUILD_DESCRIPTIONS -
[0] Name: armeabi-v7a, description: Regular ARM 32-bit
[1] Name: arm64-v8a, description: Regular ARM 64-bit
- IOS_BUILD_DESCRIPTIONS -
[0] Name: base, description: Basic xcode target (ignored on non-MacOS build)

- TARGET_BUILD_DESCRIPTIONS (ANDROID) -
[0] Name: armeabi-v7a arm64-v8a, description: Regular ARM 32-bit Regular ARM 64-bit
[1] Name: , description: 
- TARGET_BUILD_DESCRIPTIONS (IOS) -
[0] Name: base, description: Basic xcode target (ignored on non-MacOS build)

正如您在输出中看到的那样,原始数组已正确组装并且其内容已正确显示。但是在变量名替换和数组复制之后,内容被组装成一个大字符串......这完全破坏了数组的内容,因为在这种情况下它包含 IFS 分隔的值(默认为''/space)。

然后我尝试了另一种方法,我不明白为什么这个方法不起作用。我基本上创建TARGET_BUILD_OPTIONS为一个全新的数组,然后一次迭代ANDROID/IOS_BUILD_OPTIONS一个元素的内容,然后复制它。这是更新的代码:

TARGET_BUILD_OPTIONS=()
TARGET_BUILD_DESCRIPTIONS=()
if [ "${TARGET}" = "ANDROID" ]; then
    COUNTER=0
    while [ "${COUNTER}" -lt "${ANDROID_BUILD_OPTIONS_COUNT}" ]; do
        TARGET_BUILD_OPTIONS+=(${ANDROID_BUILD_OPTIONS[COUNTER]})
        TARGET_BUILD_DESCRIPTIONS+=(${ANDROID_BUILD_DESCRIPTIONS[COUNTER]})
        COUNTER=$((COUNTER + 1))
    done
else
    COUNTER=0
    while [ "${COUNTER}" -lt "${IOS_BUILD_OPTIONS_COUNT}" ]; do
        TARGET_BUILD_OPTIONS+=(${IOS_BUILD_OPTIONS[COUNTER]})
        TARGET_BUILD_DESCRIPTIONS+=(${IOS_BUILD_DESCRIPTIONS[COUNTER]})
        COUNTER=$((COUNTER + 1))
    done
fi

令我惊讶的是......这也不起作用。它似乎遍历字符串,一次一个词:

- ANDROID_BUILD_DESCRIPTIONS -
[0] Name: armeabi-v7a, description: Regular ARM 32-bit
[1] Name: arm64-v8a, description: Regular ARM 64-bit
- IOS_BUILD_DESCRIPTIONS -
[0] Name: base, description: Basic xcode target (ignored on non-MacOS build)

- TARGET_BUILD_DESCRIPTIONS (ANDROID) -
[0] Name: armeabi-v7a, description: Regular
[1] Name: arm64-v8a, description: ARM
- TARGET_BUILD_DESCRIPTIONS (IOS) -
[0] Name: base, description: Basic

非常令人惊讶的是,它与之前用于打印的代码相同。这是彼此相邻的两段代码:

# Correctly prints the complete strings one array element after the other
COUNTER=0
while [ $COUNTER -lt ${ANDROID_BUILD_OPTIONS_COUNT} ]; do
    echo "$COUNTER: ${ANDROID_BUILD_DESCRIPTIONS[COUNTER]}"
    echo "$i: ${ANDROID_BUILD_OPTIONS[i]}, ${ANDROID_BUILD_DESCRIPTIONS[i]}"
    COUNTER=$((COUNTER + 1))
done
# Copies the element one word by one word, using ' '/space as a separator?
COUNTER=0
while [ "${COUNTER}" -lt "${ANDROID_BUILD_OPTIONS_COUNT}" ]; do
    TARGET_BUILD_OPTIONS+=(${ANDROID_BUILD_OPTIONS[COUNTER]})
    TARGET_BUILD_DESCRIPTIONS+=(${ANDROID_BUILD_DESCRIPTIONS[COUNTER]})
    COUNTER=$((COUNTER + 1))
done

有谁知道引擎盖下发生了什么?我怎样才能实现我正在寻找的行为?

提前致谢。

标签: arraysbash

解决方案


问题是您已将整个数组内容作为单个字符串扩展到变量TARGET_BUILD_OPTIONS而不是数组。即,TARGET_BUILD_OPTIONS="${!varname}将内容视为单个字符串。

在这句话之后varname="${TARGET}_BUILD_OPTIONS[@]"varname就变成了ANDROID_BUILD_OPTIONS[@]。所以当你给TARGET_BUILD_OPTIONS="${!varname}"它时,它会被设置为TARGET_BUILD_OPTIONS=armeabi-v7a arm64-v8a.

另一方面,当你给它时TARGET_BUILD_OPTIONS=("${!variable}"),它确实会被视为一个数组TARGET_BUILD_OPTIONS=(armeabi-v7a arm64-v8a)

因此,如果将其扩展为数组(设置TARGET_BUILD_OPTIONS=("${!varname}")),那么您的脚本将起作用。

for TARGET in ANDROID IOS; do
    varname="${TARGET}_BUILD_OPTIONS[@]"
    TARGET_BUILD_OPTIONS=("${!varname}")
    varname="${TARGET}_BUILD_DESCRIPTIONS[@]"
    TARGET_BUILD_DESCRIPTIONS=("${!varname}")
    varname="${TARGET}_BUILD_OPTIONS_COUNT"
    TARGET_BUILD_OPTIONS_COUNT=${!varname}

    echo "- TARGET_BUILD_DESCRIPTIONS (${TARGET}) -"
    i=0
    while [ $i -lt ${TARGET_BUILD_OPTIONS_COUNT} ]; do
        echo "[$i] Name: ${TARGET_BUILD_OPTIONS[i]}, description: ${TARGET_BUILD_DESCRIPTIONS[i]}"
        i=$((i + 1))
    done
done

推荐阅读