将空格分隔的字符串读入 Bash 中的数组

Posted

技术标签:

【中文标题】将空格分隔的字符串读入 Bash 中的数组【英文标题】:Reading a space-delimited string into an array in Bash 【发布时间】:2012-03-06 19:47:12 【问题描述】:

我有一个包含空格分隔字符串的变量:

line="1 1.50 string"

我想将该字符串以空格作为分隔符并将结果存储在一个数组中,以便以下内容:

echo $arr[0]
echo $arr[1]
echo $arr[2]

输出

1
1.50
string

在某处我发现了一个不起作用的解决方案:

arr=$(echo $line)

如果我在此之后运行上面的 echo 语句,我会得到:

1 1.50 string
[empty line]
[empty line]

我也试过

IFS=" "
arr=$(echo $line)

结果相同。有人可以帮忙吗?

【问题讨论】:

在 Unix 和 Linux Stack Exchange 上查看此答案:Using sed with herestring (<<<) and read -a。 set -f; arr=($string); set +f 似乎比 read -r -a &lt;&lt;&lt; $string 快。 相关:如何将 newline-delimited 字符串转换为 bash 数组:Convert multiline string to array 在此处查看这些演示和示例:shellcheck SC2206: Quote to prevent word splitting/globbing, or split robustly with mapfile or read -a. 【参考方案1】:

为了将字符串转换为数组,从字符串创建数组,让字符串根据IFS(内部字段分隔符)变量自然分割,默认为空格字符:

arr=($line)

或使用herestring (&lt;&lt;&lt;) 运算符将字符串传递给read 命令的标准输入:

read -a arr <<< "$line"

对于第一个示例,不要$line 周围使用引号至关重要,因为这样可以将字符串拆分为多个元素。

另见:https://github.com/koalaman/shellcheck/wiki/SC2206

【讨论】:

并对漂亮的新阵列进行健全性检查:for i in $arr[@]; do echo $i; done 或只是echo $arr[@] 如果$line 中有通配符,这两种方法都可能失败。 mkdir x &amp;&amp; cd x &amp;&amp; touch A B C &amp;&amp; line="*" arr=($line); echo $#arr[@] 给 3 declare -a "arr=($line)" 将忽略带引号的字符串中的 IFS 分隔符 @Tino 否。当line='*'read -a arr &lt;&lt;&lt;$line 始终有效,但只有arr=($line) 失败。【参考方案2】:

在:arr=( $line )。 “拆分”与“glob”相关联。 通配符(*?[])将扩展为匹配的文件名。

正确的解决方案只是稍微复杂一点:

IFS=' ' read -a arr <<< "$line"

没有通配问题;分割字符设置在$IFS,变量引用。

【讨论】:

这应该是公认的答案。 accepted answer 中的声明 arr=($line) 存在通配问题。例如,尝试:line="twinkling *"; arr=($line); declare -p arr 对于 herestring &lt;&lt;&lt;,引号是可选的,但为了一致性和可读性,仍然使用双引号可能是个好主意。 另见:shellcheck SC2206: Quote to prevent word splitting/globbing, or split robustly with mapfile or read -a.【参考方案3】:

试试这个:

arr=(`echo $line`);

【讨论】:

很好——这个解决方案也适用于 Z shell,上面的一些其他方法都失败了。 它起作用了,你能解释一下它为什么起作用吗? 备注:当行中有'*'时,这也不起作用,例如line='*' 正在寻找GNU Make 4.2.1 解决方案,但没有成功 @artu-hnrq 使用sh shell。该外壳没有数组。问题是关于数组的。不能给你一个与这两个要求兼容的答案。除非您声称位置参数是 sh 中的唯一数组,然后,这:set -- $line; printf '%s\n' "$@" 将起作用。请注意,在这种情况下,全局字符仍然是一个问题。【参考方案4】:

如果需要参数扩展,那么试试:

eval "arr=($line)"

以下面的代码为例。

line='a b "c d" "*" *'
eval "arr=($line)"
for s in "$arr[@]"; do 
    echo "$s"
done

如果当前目录包含文件a.txtb.txtc.txt,则执行代码将产生以下输出。

a
b
c d
*
a.txt
b.txt
c.txt

【讨论】:

正在寻找GNU Make 4.2.1 的解决方案,但不是这样【参考方案5】:
line="1 1.50 string"

arr=$( $line | tr " " "\n")

for x in $arr
do
echo "> [$x]"
done

【讨论】:

循环是错误的,它将数组分割得很好,管道进入tr是多余的,但它应该循环"$arr[@]",而不是$arr

以上是关于将空格分隔的字符串读入 Bash 中的数组的主要内容,如果未能解决你的问题,请参考以下文章

将带有空格分隔符的字符串转换为数组。并输出这个数组,就像一个字符串

在C ++中将用空格分隔的字符串读入向量[关闭]

C++输入多行数字到数组

Java - 如何将用空格分隔的整数读入数组

在bash中,如何将N个参数连接在一起作为空格分隔的字符串

如何在不折叠空格的情况下在 bash 脚本中拆分制表符分隔的字符串?