我想递归地列出目录中与给定输入模式匹配的所有文件使用 ls。 (哦,这是在 Bash 中)。
我能想到的使用 ls 执行此操作的唯一方法是shopt -s extglob
然后使用ls --ignore=pattern
具有扩展 glob negate 模式的选项!( pattern-list )
。似乎有点迂回地在忽略中否定,但否则通配符不会递归。
假设我已经有要查找的目录dir
和要与 as 匹配的模式file
,这是我当前的尝试:
ls -AR --ignore='!('"${file}"')' ${dir}
但是,这似乎没有达到预期的效果,例如在测试用例中,目录结构给出以下输出ls -AR
:
.:
a a.c b b.c c c.h s
./s:
a a.c b b.c c c.h
我的命令与file = *.c
(dir = s
完整命令ls -AR --ignore=!(*.c) s
:)给出以下输出:
./s:
a a.c b b.c c c.h
我知道我可以很容易地将它输入 grep 中,并执行类似的操作ls -AR s | grep -v '.*.c'
并获得如下输出:
s:
a
b
c
c.h
但我正在寻找一种方法来做到这一点ls
。
抱歉,如果我完全不清楚,这是我第一次访问 StackExchange 网站。
提前致谢!
答案1
globstar
添加shell 选项和-d
标志以ls
不自动列出目录内容怎么样?
shopt -s extglob
shopt -s globstar
ls -d **/!(*.c)
答案2
GNUls
--ignore
选项采用标准文件名模式,而不是ksh
扩展文件名模式(bash
(且bash
仅不是ls
)可识别的内容extglob
)
所以你可以这样做:
ls -AR --ignore='*.[ch]' --ignore='*.cpp'
但你不能这样做:
ls -AR --ignore='!(*.[ch]|*.cpp)'
这只会忽略名为的文件:!(foo.c|bar.cpp)
.
在 中ls -AR --ignore=!(*.c)
,由于该模式没有被引用,因此bash
在将其传递给 之前会尝试对其进行扩展ls
。因此它会在当前目录中查找名称以 . 开头"--ignore="
且不以 . 结尾的文件".c"
。例如,如果有两个文件,一个名为--ignore=foo
,一个名为--ignore=bar
,它将ls
使用这四个参数运行:"ls"
, "-AR"
, "--ignore=bar"
, "--ignore=foo"
。
你可以做(用GNU find)。
find . -regextype posix-extended -regex '.*\.([ch]|cpp)' -ls
或者使用任何 POSIX find
:
find . \( -name '*.[ch]' -o -name '*.cpp' \) -exec ls -ld {} +
或者假设没有目录的符号链接:
shopt -s extglob globstar dotglob failglob
ls -ld -- **/*.@([ch]|cpp)
这次,bash
确实扩展了通配模式并将文件列表传递到ls
.