如何在Bash中将字符串拆分成数组?

30 浏览
0 Comments

如何在Bash中将字符串拆分成数组?

在Bash脚本中,我想将一行文本分割成多个部分并存储到一个数组中。\n例如,给定以下行:\n

巴黎,法国,欧洲

\n我希望得到的数组如下所示:\n

array[0] = 巴黎
array[1] = 法国
array[2] = 欧洲

\n最好使用简单的实现方法;速度不重要。我应该如何实现?

0
0 Comments

在Bash中,有时候我们需要将一个字符串分割成一个数组。下面是一种方法,不需要设置IFS(内部字段分隔符):

string="1:2:3:4:5"
set -f                      # 避免通配符扩展(*的展开)。
array=(${string//:/ })
for i in "${!array[@]}"
do
    echo "$i=>${array[i]}"
done

这个方法的思路是使用字符串替换操作`${string//substring/replacement}`,将字符串中所有的`substring`替换为空格,然后使用被替换后的字符串初始化一个数组`(element1 element2 ... elementN)`。

需要注意的是,这个答案使用了split+glob操作符。为了避免对一些字符(比如`*`)的展开,最好在脚本中暂停globbing。

有人使用这种方法,直到遇到了一个很长的需要分割的字符串。CPU占用率达到100%,持续了超过一分钟(然后被终止)。这很可惜,因为这种方法允许按照一个字符串来分割,而不是IFS中的某个字符。

对我来说,CPU占用率达到100%一分钟以上听起来肯定是有什么地方出了问题。那个字符串有多长,是MB还是GB级别的?我认为,通常情况下,如果你只需要对一个小字符串进行分割,你应该使用Bash内置的方法。但是如果是一个巨大的文件,我会执行像Perl这样的脚本来处理。

警告:我刚刚遇到了这个方法的一个问题。如果你的元素名为`*`,你将会得到当前工作目录的所有元素。因此,`string="1:2:3:4:*"`将会得到一些意外的、可能危险的结果,具体取决于你的实现。使用`(IFS=', ' read -a array <<< "$string")`没有遇到同样的错误,这个方法似乎是安全的。

这个方法在基本的shell中有效,而另一个答案则不行。谢谢!

引用`${string//:/ }`可以避免shell扩展的问题。

我在OSX上使用了以下方法:`array=(${string//:/ })`

和之前的回答相比,我没有得到期望的结果,而是必须使用一个未引用的版本。

编辑添加引号阻止了Shell分割并破坏了答案。这仍然容易受到`*`的展开和相关问题的影响。

这个答案基于Shell的分割,最好避免通配符扩展以避免`*`的展开。答案已经相应地进行了编辑。

没错,之前的答案对我来说确实无法工作,因为它导致了通配符扩展,通过加引号解决了这个问题。抱歉如果我有误解。

我非常喜欢这种方法,比操纵IFS要好得多,而且比"split"命令快得多。

当我尝试处理一个分隔符为"/"的字符串时,这个方法对我起作用了。谢谢!

太好了,我喜欢这个非IFS的解决方案!

大家都不知道的是,这种分割仍然使用了IFS。只是默认的IFS值是空格、制表符和换行符。

如果字符串中的元素包含空格,该怎么办?

0
0 Comments

如何在Bash中将字符串拆分为数组?

这个问题有很多错误的答案。

错误答案#1:这是对$IFS的误用。$IFS变量的值不会作为一个单一的变长字符串分隔符,而是作为一组单字符的字符串分隔符处理,read命令从输入行中分割出的每个字段可以由集合中的任何字符终止(在此示例中为逗号或空格)。

错误答案#2:即使你使用的是单字符分隔符(例如只有逗号,没有后面的空格或其他内容),如果$string变量的值恰好包含任何换行符(LF),那么read命令在遇到第一个换行符时就会停止处理。read命令每次只处理一行输入。即使你只将输入仅通过管道或重定向传递给read语句,正如我们在此示例中使用here-string机制,并且未处理的输入肯定会丢失。read命令的代码在其包含的命令结构内没有对数据流有任何了解。

错误答案#3:这种解决方案的一个不明显的潜在问题是,read命令总是会删除空的尾字段,尽管它保留其他空字段。这是一个演示:

string=', , a, , b, c, , , '; IFS=', ' read -ra a <<<"$string"; declare -p a;

## declare -a a=([0]="" [1]="" [2]="a" [3]="" [4]="b" [5]="c" [6]="" [7]="")

错误答案#4:这个解决方案与错误答案#2和#3类似,它使用了一个单字符分隔符,但是显式地将$IFS设置为仅包含输入字符串中出现的单个字符分隔符。读取字符串的字段将不会意外地在中间拆分,但它也不会在结束时过早地截断,并且可以保留空字段。然而,它无法处理多字符分隔符,这是这个解决方案的一个不幸的限制。

错误答案#5:这个解决方案将输入字符串直接粘贴到数组文字中。这实际上不是解析字符串的方法。此外,它假设$IFS变量会影响bash在所有上下文中的所有解析,这是不正确的。

错误答案#6:这个解决方案与错误答案#1类似,它设置了$IFS以包含输入字符串中的单个字符字段分隔符。它假设逗号是主要的分隔符字符,然后通过删除非-IFS表示的字符来解决此特定情况,然后使用字段分割来拆分字段。这不是一个非常通用的解决方案,并且无法处理多字符分隔符。

错误答案#7:这个解决方案使用了一个循环read命令,该命令将每行输入拆分为字段,并将字段附加到数组中。它不会自动删除字段中的前导和尾随空格,并且无法处理多字符分隔符。

错误答案#8:这个解决方案使用了readarray命令(也称为mapfile),它将字节流解析为数组变量。它不会自动删除字段中的前导和尾随空格,并且无法处理多字符分隔符。此外,此解决方案未正确解析输入字符串,实际上无法用于解析它。

因此,为了解决这个问题,我提供了正确的答案:

正确答案:使用readarray命令,并将多字符分隔符替换为单字符分隔符,然后删除数组中的最后一个元素。这个解决方案不会在字段中间错误地拆分,不会过早地截断,不会删除空字段,也不会破坏文件名扩展,并且不会自动修剪前导和尾随空格。

最后,我还提供了一个修剪方案,它使用了readarray命令的-C回调选项,可以修剪字段中的前导和尾随空格。

这个答案可能有点冗长,但是它提供了一个详细而全面的解决方案,希望对你有所帮助!

0
0 Comments

如何在Bash中将字符串拆分为数组?

在Bash中,我们可以使用IFS(Internal Field Separator)来定义用于拆分字符串的分隔符。默认情况下,IFS设置为包含空格、制表符和换行符的字符。我们可以使用IFS来指定我们想要的分隔符,然后使用read命令将字符串拆分为数组。

以下是将字符串拆分为数组的示例代码:

string="Hello,World,How,Are,You"
IFS=',' read -r -a array <<< "$string"

在上面的代码中,我们使用逗号作为分隔符将字符串拆分为数组。通过将IFS设置为逗号,然后使用read命令将$string读入到数组$array中,我们可以将字符串拆分为数组。

要访问单个元素,我们可以使用数组的索引。例如,要访问第一个元素,我们可以使用`${array[0]}`。

要遍历数组中的所有元素,我们可以使用for循环。例如:

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

要获取数组的长度,我们可以使用`${#array[@]}`。

需要注意的是,Bash数组可以是稀疏的,即索引不一定连续。我们可以删除或添加元素,然后索引就不再连续。要获取数组中的索引和值,我们可以使用`${!array[@]}`。

以上是在Bash中将字符串拆分为数组的基本方法和操作。通过使用适当的分隔符和数组操作,我们可以轻松地将字符串拆分为数组,以便进行进一步的处理和操作。

0