Xiong Chiamiov
Xiong Chiamiov

Reputation: 13754

Using find to locate files that match one of multiple patterns

I was trying to get a list of all python and html files in a directory with the command find Documents -name "*.{py,html}".

Then along came the man page:

Braces within the pattern (‘{}’) are not considered to be special (that is, find . -name 'foo{1,2}' matches a file named foo{1,2}, not the files foo1 and foo2.

As this is part of a pipe-chain, I'd like to be able to specify which extensions it matches at runtime (no hardcoding). If find just can't do it, a perl one-liner (or similar) would be fine.

Edit: The answer I eventually came up with include all sorts of crap, and is a bit long as well, so I posted it as an answer to the original itch I was trying to scratch. Feel free to hack that up if you have better solutions.

Upvotes: 449

Views: 521957

Answers (12)

RichieHindle
RichieHindle

Reputation: 281835

Use -o, which means "or":

find Documents \( -name "*.py" -o -name "*.html" \)

You'd need to build that command line programmatically, which isn't that easy.

Are you using bash (or Cygwin on Windows)? If you are, you should be able to do this:

ls **/*.py **/*.html

which might be easier to build programmatically.

Upvotes: 640

netskink
netskink

Reputation: 4539

This will find all .c or .cpp files on linux

$ find . -name "*.c" -o -name "*.cpp"

You don't need the escaped parenthesis unless you are doing some additional mods. Here from the man page they are saying if the pattern matches, print it. Perhaps they are trying to control printing. In this case the -print acts as a conditional and becomes an "AND'd" conditional. It will prevent any .c files from being printed.

$ find .  -name "*.c" -o -name "*.cpp"  -print

But if you do like the original answer you can control the printing. This will find all .c files as well.

$ find . \( -name "*.c" -o -name "*.cpp" \) -print

One last example for all c/c++ source files

$ find . \( -name "*.c" -o -name "*.cpp"  -o -name "*.h" -o -name "*.hpp" \) -print

Upvotes: 57

eQ19
eQ19

Reputation: 10711

Braces within the pattern \(\) is required for name pattern with or

find Documents -type f \( -name "*.py" -or -name "*.html" \)

While for the name pattern with and operator it is not required

find Documents -type f ! -name "*.py" -and ! -name "*.html" 

Upvotes: 4

Code42
Code42

Reputation: 2502

What about

ls {*.py,*.html}

It lists out all the files ending with .py or .html in their filenames

Upvotes: 0

user7531934
user7531934

Reputation: 19

find MyDir -iname "*.[j][p][g]"
+
find MyDir -iname "*.[b][m][p]"
=
find MyDir -iname "*.[jb][pm][gp]"

Upvotes: 1

intelekt
intelekt

Reputation: 1208

Some editions of find, mostly on linux systems, possibly on others aswell support -regex and -regextype options, which finds files with names matching the regex.

for example

find . -regextype posix-egrep -regex ".*\.(py|html)$" 

should do the trick in the above example. However this is not a standard POSIX find function and is implementation dependent.

Upvotes: 98

PaSe
PaSe

Reputation: 103

My default has been:

find -type f | egrep -i "*.java|*.css|*.cs|*.sql"

Like the less process intencive find execution by Brendan Long and Stephan202 et al.:

find Documents \( -name "*.py" -or -name "*.html" \)

Upvotes: 4

Stephan202
Stephan202

Reputation: 61589

You could programmatically add more -name clauses, separated by -or:

find Documents \( -name "*.py" -or -name "*.html" \)

Or, go for a simple loop instead:

for F in Documents/*.{py,html}; do ...something with each '$F'... ; done

Upvotes: 39

Abdul M Gill
Abdul M Gill

Reputation: 1

This works on AIX korn shell.

find *.cbl *.dms -prune -type f -mtime -1

This is looking for *.cbl or *.dms which are 1 day old, in current directory only, skipping the sub-directories.

Upvotes: 0

mnrl
mnrl

Reputation: 1705

#! /bin/bash
filetypes="*.py *.xml"
for type in $filetypes
do
find Documents -name "$type"
done

simple but works :)

Upvotes: 3

Adobe
Adobe

Reputation: 13487

I needed to remove all files in child dirs except for some files. The following worked for me (three patterns specified):

find . -depth -type f -not -name *.itp -and -not -name *ane.gro -and -not -name *.top -exec rm '{}' +

Upvotes: 1

bkidd
bkidd

Reputation: 590

I had a similar need. This worked for me:

find ../../ \( -iname 'tmp' -o -iname 'vendor' \) -prune -o \( -iname '*.*rb' -o -iname '*.rjs' \) -print

Upvotes: 13

Related Questions