对数组进行切片时,输出将作为字符串捕获在变量中。
当直接使用切片时,它将是单独的项目。
如何将切片数组保存在变量中而不将其转换为字符串?
还有其他方法或途径可以解决这个问题吗?
例子:
# setting IFS to this, no need to quote anything
IFS=$'\n'
mapfile -t arr < <(for i in {1..6}; do echo $i; done)
declare -p arr
declare -a arr=([0]="1" [1]="2" [2]="3" [3]="4" [4]="5" [5]="6")
# $() or `` give the same results
slc=`echo ${arr[@]:0:3}`
# proving that when the slice is saved as a var, it's a string
for i in $slc; do echo $i; done
1 2 3
# proving that when the slice is used directly the items are separate
for i in ${arr[@]:0:3}; do echo $i; done
1
2
3
请注意,它与已接受的答案一起工作;当IFS=$'\n'
结果相同时,带或不带引号:
IFS=$'\n'
slc=(${arr[@]:0:3})
for i in ${slc[@]}; do echo $i; done
1
2
3
答案1
在:
echo ${arr[@]:0:3}
首先,您忘记了引号,这意味着扩展受到 split+glob 的影响(使用IFS=$'\n'
,仍然在换行符上拆分,并且仍在进行通配),并且使用了echo
不能用于任意数据的内容。
echo
正在传递多个参数(切片的元素进一步受到 split+glob 的影响),并且它以空格分隔打印它们。
和:
var=`echo...`
(顺便说一句,这是旧的已弃用的命令替换形式,您应该使用var=$(echo...)
)
shell 将该输出(减去尾随换行符)收集到标量echo
变量,因为这是标量变量赋值语法,但无论如何,自从将所有内容捆绑到一个流中以来,有关每个元素开始和结束位置的信息早已丢失。
要将切片存储到变量中,您需要一个数组变量并使用数组赋值语法:
$ arr=( '*' $'\n' '' 'element '{4..6} ) # ¹
$ slc=( "${arr[@]:0:3}" )
$ typeset -p arr slc
declare -a arr=([0]="*" [1]=$'\n' [2]="" [3]="element 4" [4]="element 5" [5]="element 6")
declare -a slc=([0]="*" [1]=$'\n' [2]="")
和你做的一样:
@slc = @arr[0..2] # in perl
slc = $arr( `{seq 3} ) # in rc
set slc $arr[1..3] # in fish
slc=( "${arr[1,3]}" ) # in yash
slc=( "${(@)arr[1,3]}" ) # in zsh
并循环遍历元素:
for i in "${slc[@]}"; do
something with "$i"
done
或readarray -td '' arr < <(printf '%s\0' '*' $'\n' '' 'element '{4..6}
如果您必须使用readarray
或其用词不当的mapfile
别名,则依赖于 bash 变量或内置参数无论如何都不能包含 NUL 字符这一事实。