Centos – `find` multiple -o -name condition AND ! -name

centosfind

I'd been playing with this snippet and seems like I can't make my desired find work. I tried google but all tutorials does not seem to tackle this scenario

suppose i have the following files

test-[done].mkv
test.mkv
test2.avi
test3.mp4

what i want is for my find to select all .mkv OR .avi OR .mp4 BUT NOT those with [done] on its name

the first condition can be easily solve using

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

but I am having trouble doing the second condition, trying

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

still shows the `test-[done].mkv

test-[done].mkv
test.mkv
test2.avi
test3.mp4

trying regex because I thought there's limit to how many -name can be used, but still no luck

[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

Can somebody please help me how to work on this? Thanks!

Best Answer

For your -name version, instead of ! -name '*[done]*' you need ! -name '*\[done\]*' - otherwise it's taking the letters in brackets as a character set, and thus excluding anything that includes the letter "d" or "o" or "n" or "e" (and all of your filenames contain "e"). You were then negating that condition a second time, so that rather than excluding all files it includes all files - but a corrected version would be:

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

Your regex version is wrong because you have the $ immediately after the pattern matching [done], but in your real file name there's still a file extension after that point - but adding a .* before the $ does work.

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