如果我想删除数组中不匹配的行,这可以正常工作:
array=( ${(M)array:#*${filter}*} )
然而,它也压缩了数组。但我需要保持数组相同的长度,因为稍后我会将其与原始长度的另一个数组合并。也就是说,我想“空白”不匹配的行,但实际上并不删除它们——我不想更改数组的长度或更改匹配的行的索引号。
目前,我正在解决这个问题,方法是用虚拟字符串替换不匹配的字符串作为占位符,进行合并,然后删除虚拟字符串,但这很笨拙。
答案1
不带引号的扩展确实会删除空元素。您需要双引号和@
标志或使用[@]
它们来保留它们,就像在类似 Korn 的 shell 中一样。
您还需要使用 Korn 风格${var/pattern/replacement}
而不是${array:#pattern}
因为后者是一种消除元素,不编辑他们的内容。所以:
set -o extendedglob
array=( "${array[@]/#%^*$filter*}" )
print -rC1 -- "$array[@]"
下面#
是/
在开始处锚定匹配,%
在结尾处锚定(与 Korn shell 中相同,只是不能在 ksh 中组合它们),以便我们将模式作为一个整体进行匹配;在${param:#pattern}
运算符中,锚定是隐式的,必须与整个 whilepattern
的内容相匹配,并且它仅锚定在开头和结尾。$param
${param#pattern}
${param%pattern}
^
是extendedglob
否定运算符。
现在,zsh
扩展运算符可能会变得非常复杂,尤其是当您开始组合其中的几个运算符时,但您始终可以像在大多数其他语言中一样进行操作并迭代数组元素。
就像就地编辑元素一样:
for (( i = 1; i <= $#array; i++ ))
if [[ $array[i] != *$filter* ]] array[i]=
或者创建一个新数组:
new_array=()
for element ( "$array[@]" )
case $element in
(*$filter*) new_array+=( "$element" );;
(*) new_array+=( '' )
esac
或者:
new_array=()
for element ( "$array[@]" ) {
[[ $element = *$filter* ]] || element=
new_array+=( "$element" )
}
答案2
array=( "${(@M)array##*${filter}*}" )
这会保留数组的所有元素,对##pattern
每个元素执行最长前缀删除,但使用标志M
,以便仅保留匹配的部分。需要双引号和@
标志,以便不会从结果中删除空元素。