在Bash脚本中,我希望将一行分割成多个片段,并将它们存储在一个数组中。
例如,给定一行:
Paris, France, Europe
我想让结果数组看起来像这样:
array[0] = Paris
array[1] = France
array[2] = Europe
最好是一个简单的实现;速度并不重要。我该怎么做呢?
在Bash脚本中,我希望将一行分割成多个片段,并将它们存储在一个数组中。
例如,给定一行:
Paris, France, Europe
我想让结果数组看起来像这样:
array[0] = Paris
array[1] = France
array[2] = Europe
最好是一个简单的实现;速度并不重要。我该怎么做呢?
当前回答
由于有很多方法来解决这个问题,让我们从定义我们希望在解决方案中看到的内容开始。
Bash为此提供了一个内置的readarray。让我们使用它。 避免丑陋和不必要的技巧,如更改IFS、循环、使用eval或添加一个额外的元素然后删除它。 找到一个简单易读的方法,可以很容易地适用于类似的问题。
readarray命令最容易使用换行符作为分隔符。使用其他分隔符,它可以向数组中添加一个额外的元素。最简洁的方法是,在传入输入之前,首先将输入调整为与readarray很好地工作的表单。
本例中的输入没有多字符分隔符。如果我们应用一点常识,最好将其理解为逗号分隔的输入,其中每个元素可能需要修剪。我的解决方案是用逗号将输入分割成多行,修饰每个元素,并将其全部传递给readarray。
string=' Paris,France , All of Europe '
readarray -t foo < <(tr ',' '\n' <<< "$string" |sed 's/^ *//' |sed 's/ *$//')
# Result:
declare -p foo
# declare -a foo='([0]="Paris" [1]="France" [2]="All of Europe")'
编辑:我的解决方案允许逗号分隔符周围的间距不一致,同时还允许元素包含空格。很少有其他解决方案可以处理这些特殊情况。
我也避免了那些看起来像黑客的方法,比如创建一个额外的数组元素,然后删除它。如果你不同意这是最好的答案,请留下评论来解释。
如果您想在Bash中使用更少的子shell尝试相同的方法,这是可能的。但是结果很难阅读,并且这种优化可能是不必要的。
string=' Paris,France , All of Europe '
foo="${string#"${string%%[![:space:]]*}"}"
foo="${foo%"${foo##*[![:space:]]}"}"
foo="${foo//+([[:space:]]),/,}"
foo="${foo//,+([[:space:]])/,}"
readarray -t foo < <(echo "$foo")
其他回答
当我想解析一个输入时,我看到了这篇文章: word1 word2,…
以上这些对我都没有帮助。使用awk解决了这个问题。如果它能帮助某人:
STRING="value1,value2,value3"
array=`echo $STRING | awk -F ',' '{ s = $1; for (i = 2; i <= NF; i++) s = s "\n"$i; print s; }'`
for word in ${array}
do
echo "This is the word $word"
done
不要更改IFS!
下面是一个简单的bash一行代码:
read -a my_array <<< $(echo ${INPUT_STRING} | tr -d ' ' | tr ',' ' ')
接受的答案适用于一行中的值。如果变量有几行:
string='first line
second line
third line'
我们需要一个非常不同的命令来获取所有的行:
While read -r line;做线+ =(“美元线”);完成了< < <字符串" $ "
或者更简单的bash readarray:
readarray -t lines <<<"$string"
利用printf特性很容易打印所有行:
printf ">[%s]\n" "${lines[@]}"
>[first line]
>[ second line]
>[ third line]
下面是一种不设置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操作符。因此,为了防止某些字符(如*)的扩展,暂停该脚本的通配符是个好主意。
这类似于Jmoney38的方法,但是使用sed:
string="1,2,3,4"
array=(`echo $string | sed 's/,/\n/g'`)
echo ${array[0]}
打印1