在 zsh 中使用大括号扩展匹配文件

在 zsh 中使用大括号扩展匹配文件

bash我可以使用花括号来模式匹配多个文件,例如

ls *.{dot,svg,err}

如果没有特定扩展名的文件,我会收到警告,但将列出其余文件。

ls: 无法访问 '*.err': 没有这样的文件或目录

然而zsh我得到一个错误,而不是无输出是为现有文件生成的。

zsh:未找到匹配项:*.err

这也适用于删除,尝试使用以下命令删除文件:

rm -f *.{dot,svg,err}

将删除所有匹配的文件,而bash不会出现任何错误或警告,但zsh会出错并且根本不删除任何内容。

有没有一种方法可以使zsh行为与 相同bash,或者是否有另一种方法可以轻松删除/列出现有文件?


显然我可以做类似的事情find . -name '*.dot' -or -name '*.svg' -or -name '.err' | xargs rm,但这并不是特别容易/实用。

答案1

你没有得到警告中bash,你得到一个错误by ls(您会发现ls退出状态为非 0,这表明它已失败)。

zshand中bash{...}不是一个通配符,它​​是在通配符之前发生的扩展。

在:

ls -d -- *.{dot,svg,err}

(你忘记了-d--顺便说一句),shell 扩展了第{...}一个:

ls -d -- *.dot *.svg *.err

然后执行 glob。bash与大多数类似 Bourne 的 shell 一样,它有一个缺陷,即不匹配的 glob 会按原样传递。当 on 时zsh,不匹配的 glob 是一个错误。

看看如果没有名为nor的文件, rm -f [ab].cinbash如何删除该文件。在 中,你会得到一个[ab].ca.cb.czsh不匹配错误代替。请参阅failglob中的选项bash以获得类似的行为。

ls -d -- *.{dot,svg,err}(N)

inzsh将在所有 3 个 glob 上启用该nullglob选项,这样如果 glob 不匹配,它们就会被删除,但这可能不是您想要的,因为如果没有一个 glob 与任何文件匹配,则命令将变为:

ls -d --

它将列出.(当前目录)。

这里最好是使用glob 匹配具有 3 个扩展名之一的文件:

ls -d -- *.(dot|svg|err)

这将为 提供一个排序的文件列表lsls除非没有找到与该模式匹配的文件,否则将运行。

您还可以选择使用或 来启用sh/ bash(伪造的 IMO)行为。稍微好一点的方法是启用该行为(这也是 Bourne shell 发布之前 Unix shell 的行为):emulate shunsetopt nomatchcsh

setopt cshnullglob

使用该选项,仅在以下情况下才会取消该命令全部命令行上的 glob 无法匹配。如果至少有一个匹配,则所有不匹配的都将被删除,因此:

ls -d -- *.{dot,svg,err}

将扩展dotsvgerr依次省略缺失的。

如果您想比较不同方法对参数顺序的影响,您需要一个ls在显示之前不对其进行排序的命令(与 相反)。使用 GNU ls,您可以传递该-U选项,或者因为ls仅在此处打印其参数,所以只需使用printf '%s\n' *...即可。

答案2

固定在(N)图案上;这告诉 zsh 不要因为缺少匹配而感到不安。

rm -f *.{dot,svg,err}(N)

这是一个zsh全局功能。man zshexpn更多详情请参见;在“全局限定符”下。它被注释为“为当前模式设置 NULL_GLOB 选项”。

相关内容