`find` 多个 -o -name 条件 AND !-姓名

arv*_*vil 3 find centos

我一直在玩这个片段,似乎我无法完成我想要的find工作。我试过谷歌,但所有教程似乎都没有解决这种情况

假设我有以下文件

test-[done].mkv
test.mkv
test2.avi
test3.mp4
Run Code Online (Sandbox Code Playgroud)

我想要的是让我find选择所有.mkv OR .avi OR .mp4但不是那些[done]名字上的

第一个条件可以很容易地解决使用

find * \( -name '*.mkv' -o -name '*avi' -o -name '*mp4' -o -name '*flv' -o -name '*ogg' -o -name '*mov' \) -print

但我在做第二个条件时遇到了麻烦,尝试

find * \( -name '*.mkv' -o -name '*avi' -o -name '*mp4' -o -name '*flv' -o -name '*ogg' -o -name '*mov' \) ! \( ! -name '*[done]*' \) -print

仍然显示`test-[done].mkv

test-[done].mkv
test.mkv
test2.avi
test3.mp4
Run Code Online (Sandbox Code Playgroud)

尝试正则表达式,因为我认为可以使用的 -name 数量是有限的,但仍然没有运气

[root@xxxx]# ls
test-[done].mkv  test.mkv  test2.avi  test3.mp4
[root@xxxx]# find * \( -name '*.mkv' -o -name '*avi' -o -name '*mp4' -o -name '*flv' -o -name '*ogg' -o -name '*mov' \) ! \( -regex '.*\(\[done\]\)$' \) -print
test-[done].mkv
test.mkv
test2.avi
test3.mp4
Run Code Online (Sandbox Code Playgroud)

有人可以帮我解决这个问题吗?谢谢!

god*_*eek 5

对于您的-name版本,而不是! -name '*[done]*'您需要! -name '*\[done\]*'- 否则它将括号中的字母作为字符集,从而排除任何包含字母“d”或“o”或“n”或“e”(以及您的所有文件名)包含“e”)。然后您第二次否定该条件,因此不是排除所有文件,而是包含所有文件 - 但更正后的版本将是:

find * \( -name '*.mkv' -o -name '*avi' -o -name '*mp4' -o -name '*flv' -o -name '*ogg' -o -name '*mov' \) \( ! -name '*\[done\]*' \) -print
Run Code Online (Sandbox Code Playgroud)

您的正则表达式版本是错误的,因为您$在模式匹配之后立即有[done],但是在您的真实文件名中,在那之后仍然有一个文件扩展名 - 但.*$确实有效之前添加了。

find * \( -name '*.mkv' -o -name '*avi' -o -name '*mp4' -o -name '*flv' -o -name '*ogg' -o -name '*mov' \) ! \( -regex '.*\(\[done\]\).*$' \) -print
Run Code Online (Sandbox Code Playgroud)