在Bash脚本中,我希望将一行分割成多个片段,并将它们存储在一个数组中。

例如,给定一行:

Paris, France, Europe

我想让结果数组看起来像这样:

array[0] = Paris
array[1] = France
array[2] = Europe

最好是一个简单的实现;速度并不重要。我该怎么做呢?


当前回答

另一种方法是:

string="Paris, France, Europe"
IFS=', ' arr=(${string})

现在你的元素被存储在“arr”数组中。 要遍历元素:

for i in ${arr[@]}; do echo $i; done

其他回答

下面是一种不设置IFS的方法:

string="1:2:3:4:5"
set -f                      # avoid globbing (expansion of *).
array=(${string//:/ })
for i in "${!array[@]}"
do
    echo "$i=>${array[i]}"
done

这个想法是使用字符串替换:

${string//substring/replacement}

将所有匹配的$substring替换为空白,然后使用替换后的字符串初始化数组:

(element1 element2 ... elementN)

注意:这个答案使用了split+glob操作符。因此,为了防止某些字符(如*)的扩展,暂停该脚本的通配符是个好主意。

#!/bin/bash

string="a | b c"
pattern=' | '

# replaces pattern with newlines
splitted="$(sed "s/$pattern/\n/g" <<< "$string")"

# Reads lines and put them in array
readarray -t array2 <<< "$splitted"

# Prints number of elements
echo ${#array2[@]}
# Prints all elements
for a in "${array2[@]}"; do
        echo "> '$a'"
done

此解决方案适用于较大的分隔符(多个字符)。 如果在原始字符串中已经有换行符,则不工作

如果你使用macOS,不能使用readarray,你可以简单地这样做-

MY_STRING="string1 string2 string3"
array=($MY_STRING)

要遍历元素:

for element in "${array[@]}"
do
    echo $element
done

更新:不要这样做,由于eval的问题。

不那么讲究礼节的:

IFS=', ' eval 'array=($string)'

e.g.

string="foo, bar,baz"
IFS=', ' eval 'array=($string)'
echo ${array[1]} # -> bar

输入代码here多字符分隔符解决方案。

正如其他人在这篇文章中指出的,OP的问题给出了一个用逗号分隔的字符串被解析成数组的例子,但没有指出他/她是否只对逗号分隔符、单字符分隔符或多字符分隔符感兴趣。

由于谷歌倾向于将这个答案排在搜索结果的顶部或附近,所以我想为读者提供一个关于多个字符分隔符问题的有力答案,因为至少有一个回答也提到了这个问题。

如果您正在寻找多字符分隔符问题的解决方案,我建议您查看Mallikarjun M的帖子,特别是来自gniourf_gniourf的回复 谁提供了这个优雅的纯BASH解决方案使用参数展开:

#!/bin/bash
str="LearnABCtoABCSplitABCaABCString"
delimiter=ABC
s=$str$delimiter
array=();
while [[ $s ]]; do
    array+=( "${s%%"$delimiter"*}" );
    s=${s#*"$delimiter"};
done;
declare -p array

链接到引用的评论/引用的帖子

链接到引用的问题:如何在bash中拆分多字符分隔符上的字符串?


2022年8月3日

Xebeche在下面的评论中提出了一个很好的观点。在审查了他们建议的编辑之后,我修改了gniourf_gniourf提供的脚本,并添加了注释,以便于理解脚本正在做什么。我还将双括号[[]]改为单括号,以提高兼容性,因为许多SHell变体不支持双括号表法。在本例中,对于BaSH,逻辑在单括号或双括号内工作。

#!/bin/bash
  
str="LearnABCtoABCSplitABCABCaABCStringABC"
delimiter="ABC"
array=()

while [ "$str" ]; do

    # parse next sub-string, left of next delimiter
    substring="${str%%"$delimiter"*}" 

    # when substring = delimiter, truncate leading delimiter
    # (i.e. pattern is "$delimiter$delimiter")
    [ -z "$substring" ] && str="${str#"$delimiter"}" && continue

    # create next array element with parsed substring
    array+=( "$substring" )

    # remaining string to the right of delimiter becomes next string to be evaluated
    str="${str:${#substring}}"

    # prevent infinite loop when last substring = delimiter
    [ "$str" == "$delimiter" ] && break

done

declare -p array

不加评论:

#!/bin/bash
str="LearnABCtoABCSplitABCABCaABCStringABC"
delimiter="ABC"
array=()
while [ "$str" ]; do
    substring="${str%%"$delimiter"*}" 
    [ -z "$substring" ] && str="${str#"$delimiter"}" && continue
    array+=( "$substring" )
    str="${str:${#substring}}"
    [ "$str" == "$delimiter" ] && break
done
declare -p array