假设我想从数组的所有元素中删除前两个和最后三个字符,例如
results=( QK9H9UtADCgnG AlaLkCADjQ krsxseW8H1VrU 6nBG94ZbCWQ )
我想结束
results=( 9H9UtADC aLkCA sxseW8H1 BG94Zb )
除了循环元素并使用之外,${element:2:-3}
是否有一个标志或某种组合允许执行类似的操作${(⭕)results:2:-3}
,以便子字符串扩展影响每个元素而不是影响数组?
如果重要的话,在我的特殊情况下,数组可以绝不有空元素,元素可以不是包含任何类型的空白字符,并且提取规则始终是左>P+S那就是L任何元素的长度总是大于元素的总长度S后缀和磷修复要删除的内容。
我对修改字符串和使用文本处理工具不感兴趣。我目前正在使用一个函数来循环,正如我上面所说的,所以这不是尝试减少输入的问题,我只是好奇这是否可能,因为我浏览了手册,但找不到方法来做到这一点。
答案1
请注意,${string:offset:length}
来自 ksh93 并不是原生的 zsh 方式,它只是最近为了与 ksh93 / bash 兼容而添加的。
在 zsh 中,您宁愿这样做$string[first,last]
(早于 ksh93)。
但无论如何,无论是 zsh$var[first,last]
还是 ksh93-style ${var:offset:length}
,这些都是可以应用于字符串和数组的运算符(在 zsh 中,与 bash/ksh 相反,数组和标量是两种独立的变量类型,其中运算符可以以不同的方式应用),在第一种情况下为您提供一个子字符串,在第二种情况下为您提供元素的子集。
据我所知,您无法告诉 zsh 这些将应用于每个字符串元素而不是整个数组。
${results[1][3,-4]}
(或${results[1]:2:-3}
) 有效,但${results[1,2][3,-4]}
不会${results[1,2]}
产生数组,而不是字符串,因此[3,-4]
按数组应用。
然而在这里,您可以采取不同的方法。
例如,您可以将${string#pattern}
和${string%pattern}
ksh 样式运算符应用到每个元素:
results=( ${${results#??}%???} )
或者删除任意数量的前导和尾随字符:
set -o extendedglob
results=( ${${results#?(#c5)}%?(#c8)} )
您还可以使用 ksh93-style 对每个元素进行任意修改${array/pattern/replacement}
,例如:
set -o extendedglob
results=( ${results/(#m)*/$MATCH[3,-4]} )
也可以看看
results=( ${results/(#b)??(*)???/$match[1]} )
这只会修改至少有 5 个字符的元素(与results=( "${results[@]/??@(*)???/\1}" )
ksh93 中相同)。
另一种复杂的方法:
() { results=( ${(e)argv} ); } '${results['{1..$#results}'][3,-4]}'
我们将${results[1][3,-4]}
${results[2][3,-4]}
etc 传递给一个匿名函数,在该函数中我们使用标志e
来评估它们并将其分配回数组。
[@]
(在所有这些中,如果您想保留空元素,包括那些在修剪后变为空的元素,请使用带和引号的变体)。
答案2
这是修剪数组元素的一种方法:
trimmed_array=( $(printf '%s\n' "${results[@]}" | cut -c 3- | rev | cut -c 4- | rev) )
检查新数组:
printf '%s\n' "${trimmed_array[@]}"
9H9UtADC
aLkCA
sxseW8H1
BG94Zb
每个管道部分的动作都很容易检查和理解。