为了解决这个问题,假设 glob/a/b/c/*
不产生任何匹配项。
这意味着以下测试应该失败(换句话说,它应该产生非零$?
):
[[ -n /a/b/c/*(#qN) ]]
事实上是这样的如果我直接在(zsh)命令行上运行测试。但是,如果我坚持完全相同的测试在脚本中,它成功了,这不是预期的行为。
如果我使用该标志运行相同的脚本-x
,则生成的跟踪将测试显示为
[[ -n '/a/b/c/*(#qN)' ]]
我不明白为什么单引号出现在 test 的参数周围;在脚本的源代码中根本没有引号。
如果 zsh 自动插入这些单引号,这将解释文本成功的原因。
问题:
- 为什么此表达式的命令行版本和脚本版本之间存在差异?
- 我需要做什么才能使脚本中的测试(正确)失败?
答案1
来自CONDITIONAL EXPRESSIONS
zsh 手册的部分:
文件名生成不会在任何形式的条件参数上执行。但是,在正常 shell 扩展有效且选项 EXTENDED_GLOB 有效的任何情况下,都可以通过在字符串末尾使用 (#q) 形式的显式 glob 限定符来强制执行此操作。
换句话说,在脚本中,如果extendedglob
未设置该选项,/a/b/c/*(#qN)
则被视为文字字符串。
答案2
检查 glob 是否与任何文件匹配的更好的习惯用法(IMO)是:
()(($#)) /a/b/c/*(NY1)
这并不需要extendedglob
的特殊情况[[ -n ...(#qN) ]]
。而且由于Y1
在第一场比赛就停止,效率也更高。
它的工作原理是将 glob 扩展传递给一个匿名函数,该函数的主体是(($#))
算术表达式,如果该匿名函数的参数数量非零,则该算术表达式返回 true。
您可以将其扩展到以下内容:
if ()(( $# >= 3 )) /a/b/c*(NY3); then
echo there were at least 3 matching files.
fi