Skip to content
Advertisement

Exclude list of file extensions from find in bash shell

I want to write a cleanup routine for my make file that removes every thing except the necessary source files in my folder. For example, my folder contains files with the following extensions: .f .f90 .F90 .F03 .o .h .out .dat .txt .hdf .gif.

I know I can accomplish this with:

find . -name ( '*.o' '*.out' '*.dat' '*.txt' '*.hdf' '*.gif' ) -delete

Using negation, I can do this:

find . -not -name '*.f*' -not -name '*.F*' -not -name '*.h' -delete

But, when I try to do this:

find . -not -name ( '*.f*' '*.F*' '*.h' )

I get an error:

find: paths must exceed expression: [first expression in the above list]

(In this case, I would get: find: paths must exceed expression: *.f* )

Can you explain why this happens, and how to do what I am trying to do? I just hate writing -not -name every time I want to add a file extension to the list. Also, I want to find out why this is giving me an error so that I can learn Linux better.

Thanks!

Advertisement

Answer

find . -not -name ( '*.f' '*.F' '*.h' )

is interpreted as

find
    .                      # path to search
    -not                   # negate next expression
    -name (               # expression for files named "("
    '*.f' '*.F' .'*.h' )  # more paths to search?

leading to the error.

Since these are single-letter extensions, you can collapse them to a single glob:

find . -not -name '*.[fFh]'

but if they are longer, you have to write out the globs

find . -not -name '*.f' -not -name '*.F' -not -name '*.h'

or

find . -not ( -name '*.f' -o -name '*.F' -o -name '*.h' )

or switch to using regular expressions.

find . -not -regex '.*.(f|F|h)$'

Note that regular expressions in find is not part of the POSIX standard and might not be available in all implementations.

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement