是否有一个较短的相当于 long/path/**/^*.(complex|pattern)~long/path/(bad-1|bad-2)/*(.) 不需要重复 long/path/ ?

是否有一个较短的相当于 long/path/**/^*.(complex|pattern)~long/path/(bad-1|bad-2)/*(.) 不需要重复 long/path/ ?

这是一个 zsh 扩展的 glob 模式。要点是将目录层次结构下的所有文件与模式匹配,特定子层次结构除外。标题中的模式有效,但我想要一些不需要重复的东西long/path/

我尝试了以下方法:

long/path/(^(bad-1|bad-2)/|)**/^*.(complex|pattern)(.)
long/path/(**~(bad-1|bad-2)/*)/^*.(complex|pattern)(.)

添加KSH_GLOB

long/path/?(^(bad-1|bad-2)/)**/^*.(complex|pattern)(.)

它们都会导致错误的模式错误。问题似乎出/在括号中。文档说:

如上所述,用作目录分隔符的“/”可能不会出现在括号内

这让我很困惑,因为(dir/)#这是一个很好的模式。文档中甚至提到了这一点:

“(foo/)#”形式的路径名组件与由零个或多个与模式 foo 匹配的目录组成的路径相匹配。

我猜这是个例外。

需要明确的是,我正在寻找同等的东西。这不包括:

long/path/^(bad-1|bad-2)/**/^*.(complex|pattern)(.)

因为它排除了诸如long/path/good.pattern, 和

long/path/(^(bad-1|bad-2)/)#/^*.(complex|pattern)(.)
long/path/**/^*.(complex|pattern)~*/(bad-1|bad-2)/*(.)

因为这些排除了诸如以下内容之类的内容long/path/good/bad-1

编辑:顺便提一下,解决方案不一定需要仅使用通配符。如果可以通过添加大括号或历史扩展或其他一些 zsh 工具来完成,那就太好了。

编辑2:按照我自己的想法,我尝试了历史扩展:

long/path/**/^*.(complex|pattern)~!{#$:s/\**//}/(bad-1|bad-2)/*(.)

然而,这失败了,因为 1)当前行的最后一个单词是扩展所在行之前的一个单词,2)因为历史替换似乎是在全局扩展之后完成的(我一定在这里误解了一些东西,因为这似乎违背文档;也许所有扩展都是逐字完成的)。

我还尝试过大括号扩展:

( IFS=\~; printf "%s\n" long/path/{**/^*.(complex|pattern),(bad-1|bad-2)/*(.)} )

它不起作用。 2 个 glob 模式仍然被视为单独的单词,而不是连接成单个模式。我想IFS这里没有考虑到。说得通。

我还尝试了全局限定符中的替换:

+/**/^*.(complex|pattern)~+/(bad-1|bad-2)/*(.:s,+,long/path,)

但是,当然,这是行不通的,因为替换是在匹配之后而不是之前完成的。

答案1

知道了!双斜杠标记前缀:

long/path//**/^*.(complex|pattern)~*//(bad-1|bad-2)/*(.)

有时,直到您发现某些东西的用途时,您才会意识到它是一种功能。我不敢相信连续斜杠等同于一个的事实实际上可以如此有用。 :)

答案2

(...)列表/作为例外的文档:

请注意,分组不能扩展到多个目录:组内有“/”是错误的(这只适用于文件名生成中使用的模式)。有一个例外:作为完整路径段出现的一组 (pat/)# 形式可以匹配一系列目录。

否则可以通过使用表达式来过滤结果来避免重复:

% print -l a/**/*(.)
a/b/c/foo/file
a/b/d/foo/file
a/bad/e/foo/file
a/nope/d/foo/file
% print -l a/**/*(.e:'[[ $REPLY != *(bad|nope)* ]]':)
a/b/c/foo/file
a/b/d/foo/file

相关内容