使用 zsh,擦除不匹配的行,但不删除它们

使用 zsh,擦除不匹配的行,但不删除它们

如果我想删除数组中不匹配的行,这可以正常工作:

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,以便仅保留匹配的部分。需要双引号和@标志,以便不会从结果中删除空元素。

相关内容