【问题标题】:Zsh: Test whether a file matching a pattern existszsh:测试是否存在匹配模式的文件
【发布时间】:2017-01-06 09:41:27
【问题描述】:

我有一个 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 实现我的目标,没有循环?

【问题讨论】:

  • 我在尝试使用它时遇到错误,但理论上*PATTERN*(NY1) 应该只返回一个匹配项,如果有的话。
  • 太棒了!!!!为我工作!你得到什么错误?顺便说一句,如果您将评论作为答案,我会接受它作为最佳答案。虽然其他答案也显示了很棒的想法,但它们不如您的优雅。
  • 好的,看起来我对我测试它的版本感到困惑。它在 5.0.5 中不起作用(“未知文件属性:Y”,尽管手册页记录了它),但它确实在 5.2 中工作。
  • 我有 5.1.1。我猜这个功能是在 5.1 中引入的。

标签: shell zsh


【解决方案1】:

是的,在 zsh 中有。 ((#q…) 形式 glob 限定符表示法需要 setopt extendedglob。)

if [[ -n *PATTERN*(#qN) ]]; then
    this-and-that
fi

在zsh的文档"CONDITIONAL EXPRESSIONS""Glob Qualifiers"中有一些描述和类似的例子:

不会对条件的任何形式的参数执行文件名生成。但是,在正常 shell 扩展有效且选项 EXTENDED_GLOB 生效的任何情况下,都可以通过在字符串末尾使用 (#q) 形式的显式全局限定符来强制它。正常的 glob 限定符表达式可能出现在“q”和右括号之间;如果没有出现,则表达式除了导致文件名生成之外没有任何影响。文件名生成的结果结合在一起形成一个单词,就像其他形式的扩展结果一样。

文件名生成的这种特殊用途仅适用于[[ 语法。如果条件出现在[test 内置命令中,则在评估条件之前,会作为正常命令行扩展的一部分发生通配。在这种情况下,它可能会生成多个单词,这可能会混淆测试命令的语法。

例如,

[[ -n file*(#qN) ]]

当且仅当当前目录中至少有一个以字符串“file”开头的文件时,才会产生状态为零。如果没有匹配的文件,通配符 N 确保表达式为空。

-- zshmisc(1): CONDITIONAL EXPRESSIONS

--

如果设置了选项 EXTENDED_GLOB,则可以使用不同的 glob 限定符语法,即“(#qx)”,其中x 是在其他格式中使用的任何相同 glob 限定符。限定符仍必须出现在模式的末尾。但是,使用这种语法,可以将多个 glob 限定符链接在一起。它们被视为各个标志集的逻辑与。此外,由于语法明确,表达式将被视为 glob 限定符,只要其中包含的任何括号是平衡的; ‘|’、‘(’或‘~’的出现并不会否定效果。请注意,即使在模式末尾存在一个裸 glob 限定符,限定符也会以这种形式被识别,例如,如果设置了两个选项,“*(#q*)(.)”将识别可执行的常规文件;但是,为了清楚起见,可能应该避免使用混合语法。请注意,在使用“[[”形式的条件中,在字符串末尾出现带括号的表达式(#q...) 表示应该执行通配;表达式可能包含 glob 限定符,但如果它只是 (#q) 也是有效的。这不适用于模式匹配运算符的右侧,因为语法已经具有特殊意义。

-- zshexpn(1): Expansion, Filename Generation, Glob Qualifiers

【讨论】:

  • 我喜欢这个想法,但我觉得为此打开扩展通配符然后再关闭它很麻烦,所以我更喜欢 chepner 的建议。
  • 其实,如果你想在条件表达式中使用 glob,这是必要的。
  • 我认为前面的评论缺少一个“不”。语法 (#qN) 似乎在条件表达式中对我有用,而无需启用 extendedglob
【解决方案2】:

您可以做的一种方法是将找到的文件(文件名)加载到数组中,然后检查数组长度:

a=(*.txt)
echo ${#a}

【讨论】:

  • 好主意!不过应该是a=(*.txt(N))
【解决方案3】:

您可以使用Y glob 限定符来限制匹配的数量。

% echo foo*
foo foo.txt foo.zip
% echo foo*(NY1)
foo

【讨论】:

    猜你喜欢
    • 2011-04-27
    • 2022-11-16
    • 2022-06-26
    • 1970-01-01
    • 1970-01-01
    • 2011-02-16
    • 2017-07-29
    • 2017-02-08
    • 2016-12-13
    相关资源
    最近更新 更多