在Unix系统中查找不以特定扩展名结尾的文件名?

273

有没有一种简单的方法来递归查找目录层次结构中所有不以特定扩展名结尾的文件?例如,所有不是*.dll或*.exe的文件。

UNIX / GNU find非常强大,但似乎没有排除模式(或者我可能没有发现),而且我一直觉得很难使用正则表达式来查找与特定表达式不匹配的内容。

我在Windows环境中(使用大多数GNU工具的GnuWin32端口),因此我同样开放接受仅限Windows的解决方案。


这个问题在这里有更多的答案:如何列出不匹配某个模式的文件? - EvgenKo423
9个回答

435

或者不需要使用(并且不需要对其进行转义:

find . -not -name "*.exe" -not -name "*.dll"

同时也要排除目录的列出

find . -not -name "*.exe" -not -name "*.dll" -not -type d

或者以正逻辑方式表达 ;-)

find . -not -name "*.exe" -not -name "*.dll" -type f

16
“-not” 可以被替换为“'!'”(建议使用引号)。另一方面,“-name”区分大小写,而“-iname”不区分大小写。 - Ivan Chau

51
find . ! \( -name "*.exe" -o -name "*.dll" \)

3
在Solaris系统中,-not选项不太好用,但加上感叹号(!)就很好用了 :) - DmitrySandalov

10
$ find . -name \*.exe -o -name \*.dll -o -print

前两个-name选项没有-print选项,因此被跳过。其他所有内容都会被打印。


9
您可以使用grep命令来执行某些操作:
find . | grep -v '(dll|exe)$'
< p > 在 < code > grep 命令中,< code > -v 标志特指"查找不匹配该表达式的内容"。 < /p >

8
grep -v '.(dll|exe)$' 可以防止匹配到名为"dexe"的文件或目录,例如。 - drAlberT
2
这仅适用于扩展正则表达式。我不得不添加-E(或使用egrep)才能使其工作。 - joctee
1
你可以使用两个表达式代替 -Egrep -v -e '\.dll$' -e '\.exe$' - alx - recommends codidact

3
find  /data1/batch/source/export   -type f -not  -name "*.dll" -not -name "*.exe"

3

Linux/OS X:

从当前目录开始,递归查找所有以.dll或.exe结尾的文件。

find . -type f | grep -P "\.dll$|\.exe$"

从当前目录开始,递归查找所有不以.dll或.exe结尾的文件。

find . -type f | grep -vP "\.dll$|\.exe$"

注意:

(1) 在 grep 命令中,选项 P 指定我们使用 Perl 风格编写正则表达式。为了能和 grep 命令结合使用正则表达式,我认为 Perl 风格是最强大的风格。

(2) 在 grep 命令中,选项 v 会让 shell 排除所有符合正则表达式的文件。

(3) 在 ".dll$" 中,$ 字符是一个分隔符控制字符,告诉 shell 文件名字符串以 ".dll" 结尾。


2

还有一个 :-)

$ ls -ltr
总计 10
-rw-r--r--    1 scripter     linuxdumb         47 12月 23 14:46 test1
-rw-r--r--    1 scripter     linuxdumb          0 1月   4 23:40 test4
-rw-r--r--    1 scripter     linuxdumb          0 1月   4 23:40 test3
-rw-r--r--    1 scripter     linuxdumb          0 1月   4 23:40 test2
-rw-r--r--    1 scripter     linuxdumb          0 1月   4 23:41 file5
-rw-r--r--    1 scripter     linuxdumb          0 1月   4 23:41 file4
-rw-r--r--    1 scripter     linuxdumb          0 1月   4 23:41 file3
-rw-r--r--    1 scripter     linuxdumb          0 1月   4 23:41 file2
-rw-r--r--    1 scripter     linuxdumb          0 1月   4 23:41 file1
$ find . -type f ! -name "*1" ! -name "*2" -print
./test3
./test4
./file3
./file4
./file5
$

Unix find命令参考


1

使用-not与-regex一起

find . -type f -not -regex '.*\.\(exe\|dll\)'

0

如果您有一个长的扩展名列表,维护一长串-not -name 'this' -not -name 'that' -not -name 'other'将会很繁琐且容易出错,因此本页上的其他解决方案并不理想。或者,如果搜索是程序化的,并且扩展名列表是在运行时构建的,则需要更清晰地分离数据(扩展名列表)和代码(find参数)的解决方案。

对于这些情况,可能需要一种更清晰地分离数据(扩展名列表)和代码(find参数)的解决方案。假设您有以下目录和文件结构:

.
└── a
    ├── 1.txt
    ├── 15.xml
    ├── 8.dll
    ├── b
    │   ├── 16.xml
    │   ├── 2.txt
    │   ├── 9.dll
    │   └── c
    │       ├── 10.dll
    │       ├── 17.xml
    │       └── 3.txt
    ├── d
    │   ├── 11.dll
    │   ├── 18.xml
    │   ├── 4.txt
    │   └── e
    │       ├── 12.dll
    │       ├── 19.xml
    │       └── 5.txt
    └── f
        ├── 13.dll
        ├── 20.xml
        ├── 6.txt
        └── g
            ├── 14.dll
            ├── 21.xml
            └── 7.txt

你可以像这样做:
## data section, list undesired extensions here
declare -a _BADEXT=(xml dll)

## code section, this never changes
BADEXT="$( IFS="|" ; echo "${_BADEXT[*]}" | sed 's/|/\\|/g' )"
find . -type f ! -regex ".*\.\($BADEXT\)"

这将导致:

./a/1.txt
./a/b/2.txt
./a/b/c/3.txt
./a/d/4.txt
./a/d/e/5.txt
./a/f/6.txt
./a/f/g/7.txt

您可以在不更改代码块的情况下更改扩展名列表。

注意 不适用于本机OSX find - 请改用gnu find。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接