为什么这种内部扩展模式不起作用?

Why this expansion inside expansion pattern doesn't work?

假设你有这样的东西:

$ a=(fooa foob foox)                                    

那么你可以这样做:

$ b=(${(M)a:#*(a|b)}) 

到select a的元素匹配模式。

所以你有:

$ print ${(qq)b}
'fooa' 'foob'

然后你希望以某种动态方式构建模式,所以你将它放在另一个变量中,比如:

$ p="*(a|b)"

你期望这样:

$ b=(${(M)a:#$p})    

如文档所述,工作方式与以前相同,但事实并非如此:

$ print ${(qq)b} 
''

这是为什么?

因为在这种情况下 zsh 尝试 select $p 的字面值(纯字符串文本):

a=('*(a|b)' fooa foob)
p="*(a|b)"
b=(${(M)a:#$p})
print ${(qq)b}
;#⇒'*(a|b)'

我们可以通过 ${~spec} 形式告诉 zsh 将 $p 的扩展视为模式而不是文字值。

${~spec}

Turn on the GLOB_SUBST option for the evaluation of spec; if the ‘~’ is doubled, turn it off. When this option is set, the string resulting from the expansion will be interpreted as a pattern anywhere that is possible, such as in filename expansion and filename generation and pattern-matching contexts like the right hand side of the ‘=’ and ‘!=’ operators in conditions.

-- zshexpn(1): Expansion, Parameter Expansion

在这种情况下,我们可以这样使用它:

a=(fooa foob foox)
p="*(a|b)"
b=(${(M)a:#${~p}}) ;# tell zsh treat as a pattern for `$p`
print ${(qq)b}
;#⇒'fooa' 'foob'

注意:它在参数扩展标志 b 中给出了一些提示,用于将模式存储在变量值中:

b

Quote with backslashes only characters that are special to pattern matching. This is useful when the contents of the variable are to be tested using GLOB_SUBST, including the ${~...} switch.

Quoting using one of the q family of flags does not work for this purpose since quotes are not stripped from non-pattern characters by GLOB_SUBST. In other words,

   pattern=${(q)str}
   [[ $str = ${~pattern} ]]

works if $str is ‘a*b’ but not if it is ‘a b’, whereas

   pattern=${(b)str}
   [[ $str = ${~pattern} ]]

is always true for any possible value of $str.

-- zshexpn(1): Expansion, Parameter Expansion, Parameter Expansion Flags