ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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 堆栈交换:Using sed with herestring (<<<) and read -aset -f; arr=($string); set +f 似乎比 read -r -a <<< $string 快。
相关:如何将 换行符 字符串转换为 bash 数组:Convert multiline string to array

G
Gabriel Staples

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

arr=($line)

或使用 herestring (<<<) 运算符将字符串传递到 read 命令的标准输入:

read -a arr <<< "$line"

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

另请参阅:https://github.com/koalaman/shellcheck/wiki/SC2206


并对漂亮的新数组进行完整性检查:for i in ${arr[@]}; do echo $i; done
或者只是echo ${arr[@]}
如果 $line 中有通配符,这两种方法都可能失败。 mkdir x && cd x && touch A B C && line="*" arr=($line); echo ${#arr[@]} 给出 3
declare -a "arr=($line)" 将忽略带引号的字符串中的 IFS 个分隔符
@Tino 不。当 line='*' 时,read -a arr <<<$line 始终有效,但只有 arr=($line) 失败。
c
codeforester

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

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

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

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


这应该是公认的答案。 accepted answer 中的语句 arr=($line) 存在通配问题。例如,尝试:line="twinkling *"; arr=($line); declare -p arr
对于 herestring <<<,引号是可选的,但为了一致性和可读性,仍然使用双引号可能是个好主意。
g
gniourf_gniourf

尝试这个:

arr=(`echo ${line}`);

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

如果您需要参数扩展,请尝试:

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 解决方案,但不是这样
c
codemania
line="1 1.50 string"

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

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

循环是错误的,它将数组很好地拆分,管道到 tr 是多余的,但它应该循环 "${arr[@]}" 而不是 $arr