在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,这表明它已失败)。
在zsh
and中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].c
inbash
如何删除该文件。在 中,你会得到一个[ab].c
a.c
b.c
zsh
不匹配错误代替。请参阅failglob
中的选项bash
以获得类似的行为。
ls -d -- *.{dot,svg,err}(N)
inzsh
将在所有 3 个 glob 上启用该nullglob
选项,这样如果 glob 不匹配,它们就会被删除,但这可能不是您想要的,因为如果没有一个 glob 与任何文件匹配,则命令将变为:
ls -d --
它将列出.
(当前目录)。
这里最好是使用一glob 匹配具有 3 个扩展名之一的文件:
ls -d -- *.(dot|svg|err)
这将为 提供一个排序的文件列表ls
,ls
除非没有找到与该模式匹配的文件,否则将运行。
您还可以选择使用或 来启用sh
/ bash
(伪造的 IMO)行为。稍微好一点的方法是启用该行为(这也是 Bourne shell 发布之前 Unix shell 的行为):emulate sh
unsetopt nomatch
csh
setopt cshnullglob
使用该选项,仅在以下情况下才会取消该命令全部命令行上的 glob 无法匹配。如果至少有一个匹配,则所有不匹配的都将被删除,因此:
ls -d -- *.{dot,svg,err}
将扩展dot
,svg
并err
依次省略缺失的。
如果您想比较不同方法对参数顺序的影响,您需要一个ls
在显示之前不对其进行排序的命令(与 相反)。使用 GNU ls
,您可以传递该-U
选项,或者因为ls
仅在此处打印其参数,所以只需使用printf '%s\n' *...
即可。
答案2
固定在(N)
图案上;这告诉 zsh 不要因为缺少匹配而感到不安。
rm -f *.{dot,svg,err}(N)
这是一个zsh
全局功能。man zshexpn
更多详情请参见;在“全局限定符”下。它被注释为“为当前模式设置 NULL_GLOB 选项”。