我想列出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 替代方案zsh
,bash
您可以使用 ksh glob(set -o kshglob
inzsh
和shopt -s extglob
in 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