使用大括号扩展与 glob *.{a,b,}test 时忽略 zsh 中的“无匹配项”

使用大括号扩展与 glob *.{a,b,}test 时忽略 zsh 中的“无匹配项”

我想列出foldername名为 或 . 的test文件atest夹中的所有文件btest

我的第一反应就是跑ls ./foldername/*.{a,b,}test

这工作正常,除非扩展名没有任何内容atest,在这种情况下我会收到错误zsh: no matches found: ./foldername/*.atest

有什么方法可以简单地忽略此错误并打印确实存在的文件吗?

我需要它在 zsh 和 Bash 中都能工作。

答案1

ls -d ./foldername/*.{a,b,}test

{a,b,...}不是全局运算符,这是大括号扩展,首先扩展为:

ls -d ./foldername/*.atest ./foldername/*.btest ./foldername/*.test

每个 glob 都会单独扩展,如果任何 glob 不匹配,则该命令将按照您的预期被取消zsh(或fish; 在 中bash,您需要failglob获得类似行为的选项)。

在这里,您希望使用与所有这些文件匹配的单个 glob,并且仅在该 glob 与任何文件都不匹配时才取消命令:

ls -d ./foldername/*.(a|b|)test

您不想使用nullglob,就好像没有一个 glob 匹配一样,它将在ls没有参数的情况下运行,因此列出当前目录。cshnullglob在这方面更好,因为它删除了不匹配的 glob,但如果所有 glob 都无法匹配,仍然会取消命令。

您不会想使用nonomatch,因为这会给您带来破坏行为,bash这将是一种耻辱。

对于同时适用于 和 的 glob 替代方案zshbash您可以使用 ksh glob(set -o kshglobinzshshopt -s extglobin bash)。

然后,你会这样做:

ls -d ./foldername/*.@(a|b|)test

或者:

ls -d ./foldername/*.?([ab])test

添加该failglob选项bash以避免 glob 在ls不匹配时被逐字传递。

为什么 nullglob 不是默认值?了解更多信息。

答案2

最好这样做find

find ./foldername -maxdepth 1 -name '*.atest' -o -name '*.btest' -o -name '*.test'

答案3

我遇到了这个问题,首先通过破解 ls 本身来解决它。完成后,我意识到我所需要的只是简单的 C 程序:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int main(int argc, char* argv[]) {
  struct stat statbuf;
  int i;
  for( i=1; i<argc; i++ ) {
    if( stat(argv[i],&statbuf) == 0 ) {
      printf("%s\n",argv[i]);
    }
  }
}

所有这一切所做的,以及它需要做的,就是运行其命令行参数并回显与有效文件相对应的那些字符串(即 stat() 成功的文件)。

当然,我们可以使用同样简单的 Python、Perl 甚至运行 stat 的 shell 函数来模拟它,但用 C 编写它可以使其运行速度更快。

至于 hacking ls,我已经在我的个人 wiki 上进行了运行:http://linux.chalisque.net/LsIgnoreMissing

答案4

@DopeGhoti 的评论对我有用。

即,将错误重定向到/dev/null使用2>运算符,如下所示:

ls ./foldername/*.{a,b,}test 2> /dev/null

相关内容