Bash 管理空格分隔列表

Bash 管理空格分隔列表

我有一个相当复杂的 shell 脚本,它处理从文件中读取的多个值列表作为空格分隔值,例如

SET1="value1 value2 value3"

for i in ${SET1}; do
   ...

我现在想在脚本中创建一个类似格式的列表来写出。但是,如果我这样做(例如):

DISCOVERED=''
DISCOVERED+=( us-east-1 )
DISCOVERED+=( us-east-2 )
DISCOVERED+=( us-west-1 )
for REGION in ${DISCOVERED} ; do
    echo $REGION
done

我没有得到任何输出。如果我指定,我确实会得到输出in ${DISCOVERED[@]}。看来我正在使用 SET1 和 DISCOVERED 中的不同数据类型。

我可以轻松地附加到具有空格分隔值的字符串,但最终会得到需要清理的前导空格或尾随空格:

function append_discovered {
   local VALUE="$1"
   if [ -z "${DISCOVERED}" ] ; then
      DISCOVERED="$VALUE"
   else
      DISCOVERED="${DISCOVERED} ${VALUE}"
   fi
}

....但这似乎相当麻烦。

我可以将输出变量视为数组 - 但随后我需要DISCOVERED="${DISCOVERED[@]}"在适当的位置将其转换回 ( ),以使用与其他列表不同的构造来迭代此列表。

如果不是数组,我的输入数据(例如上面的 $SET1)的数据类型是什么?

有没有更简洁的方法来附加此列表并保持相同的数据类型?

答案1

看来我正在使用 SET1 和 DISCOVERED 中的不同数据类型

的确。SET1是一个字符串。您可能会将字符串值解释为多个以空格分隔的元素。DISCOVERED另一方面是一个包含多个元素的数组。

set1='this is a string of seven words'
discovered=('this' 'is' 'an' 'array' 'with' 'seven' 'elements')

echo "$set1"
echo "${discovered[@]}"

SET1问题顶部的代码的一个问题是每个元素都将被通配和扩展。因此,如果您在当前目录中调用了一个文件onebananatwo并且遇到了一个元素one*,则通配符将扩展one*onebananatwo. (为了防止这种情况发生,强烈建议使用双引号变量。)

我可以轻松地附加到具有空格分隔值的字符串,但最终会得到需要清理的前导空格或尾随空格

仅当字符串不为空时,才可以使用条件扩展来插入空格:

append_discovered() {
    local value=$1
    discovered="$discovered${discovered:+ }$value"
}

(请注意,我已经删除了非标准function关键字并将变量名称小写,这样它们就不会意外地与保留变量发生冲突。)

这是发生的事情$discovered${discovered:+ }$value

  • $discovered为空字符串时,${discovered:+ }也返回空字符串,所以结果就是$value
  • $discovered有值时,${discovered:+ }返回一个空格,因此结果是一个由单个空格组成$discovered并分隔的字符串$value

展望未来,我建议您考虑使用数组作为数组数据类型,而不是字符串中以空格分隔的元素,但我意识到将其重新安装到现有脚本中可能不具有成本效益或不明智。

答案2

在我的 Mac 的 bash 5.x 中,您的第一个语法有效:

DISCOVERED=''
DISCOVERED+=( us-east-1 )
DISCOVERED+=( us-east-2 )
DISCOVERED+=( us-west-1 )
echo ${#DISCOVERED[@]}
printf '"%s" ' "${DISCOVERED[@]}"
echo

输出是:

4
"" "us-east-1" "us-east-2" "us-west-1"

也许您希望该DISCOVERED=''语句删除所有数组元素,而不是将第一个元素设置为空字符串,因此您尝试扩展/返回第一个数组元素会使数组看起来为空?

如果您想确保清除数组变量(没有元素),我建议DISCOVERED=()unset DISCOVERED

编辑添加:

为了从数组元素生成分隔字符串,我通常使用简单的两行。此示例使用 ' :' 作为分隔符:

printf -v SET1 '%s:' "${DISCOVERED[@]}"
SET1="${SET1%:}"
echo $SET1

(我没有包含空的第一个数组元素)输出:

us-east-1:us-east-2:us-west-1

它使用内置属性printf来迭代数组元素,并将分隔符附加到每个元素。 (万岁,我不必编写循环!)第二行删除了最后的分隔符。这也可以使用空格字符作为分隔符,但是使用SET1="${DISCOVERED[@]}".让第二行去掉最后一个分隔符并不是很优雅,但它适用于许多用例,它简单、快速,并且不调用外部命令。

相关内容