我有一个glob模式 PATTERN ,并希望在Zsh中实现以下逻辑:
if a file matching *PATTERN* exists, then
do this-and-that
end
请注意,我不需要知道哪些文件实际匹配模式;只有存在某个文件(或目录)这一事实才有意义。
我找不到使用if
语句执行此操作的聪明方法,因此我使用最多执行一次的“循环”来实现它:
for f in *PATTERN*(N)
do
this-and-that
break
done
这样可行:如果没有条目匹配PATTERN,则(N)会导致错误消息被抑制并跳过循环;否则,循环体执行一次。
问题:有没有办法只用一个if
来实现我的目标,没有循环?
答案 0 :(得分:11)
是的,zsh中有。 (setopt extendedglob
形式的glob限定符表示法需要(#q…)
。)
if [[ -n *PATTERN*(#qN) ]]; then
this-and-that
fi
zsh的文档"CONDITIONAL EXPRESSIONS"和"Glob Qualifiers"中有一些描述和类似示例:
不对条件的任何形式的参数执行文件名生成。但是,在正常shell扩展有效以及选项
EXTENDED_GLOB
通过在字符串末尾使用格式为(#q)
的显式glob限定符生效时,可以强制它。正常的glob限定符表达式可能出现在“q
”和右括号之间;如果没有出现,则表达式除了导致文件名生成之外没有效果文件名生成的结果连接在一起形成一个单词,与其他形式的扩展结果一样。文件名生成的这种特殊用法仅适用于
[[
语法。如果条件发生在[
或test
内置命令中,则在评估条件之前,会发生globbing作为正常命令行扩展的一部分。在这种情况下,它可能会生成多个可能会混淆测试命令语法的单词。例如,
当且仅当当前目录中至少有一个文件以字符串“
[[ -n file*(#qN) ]]
file
”开头时,才会生成状态零。如果没有匹配的文件,globbing限定符
N
可确保表达式为空。
-
如果设置了选项
EXTENDED_GLOB
,则可以使用不同的glob限定符语法,即“(#qx)
”,其中x
是另一种格式中使用的任何相同的glob限定符。限定符必须仍出现在模式的末尾。但是,使用此语法可以将多个glob限定符链接在一起。它们被视为各组标志的逻辑AND。此外,由于语法是明确的,表达式将被视为glob限定符,只要其中包含的任何括号都是平衡的; “|
”,“(
”或“~
”的出现不会否定效果。请注意,即使在模式的末尾存在裸的glob限定符,也会以此形式识别限定符,例如,如果设置了两个选项,“*(#q*)(.)
”将识别可执行的常规文件;但是,为了清楚起见,应该避免使用混合语法。请注意,在使用“[[
”形式的条件下,字符串末尾存在带括号的表达式(#q...)
表示应该执行globbing;表达式可能包含glob限定符,但如果它只是(#q)
,它也是有效的。这不适用于模式匹配运算符的右侧,因为语法已经具有特殊意义。-
zshexpn(1): Expansion, Filename Generation, Glob Qualifiers
答案 1 :(得分:1)
您可以做的一种方法是,将找到的文件(文件名)加载到数组中,并检查数组长度:
a=(*.txt)
echo ${#a}
答案 2 :(得分:1)
您可以使用Y
glob限定符来限制匹配数。
% echo foo*
foo foo.txt foo.zip
% echo foo*(NY1)
foo