忽略递归 ls 中与否定 extglob 模式的所有匹配

忽略递归 ls 中与否定 extglob 模式的所有匹配

我想递归地列出目录中与给定输入模式匹配的所有文件使用 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 = *.cdir = 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.

相关内容