是否可以将子字符串扩展应用于 zsh 数组的所有元素?

是否可以将子字符串扩展应用于 zsh 数组的所有元素?

假设我想从数组的所有元素中删除前两个和最后三个字符,例如

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

每个管道部分的动作都很容易检查和理解。

相关内容