Using find to find files WITH a certain pattern and not other pattern - linux

I want to use find to find files with _101_ in the name and not .jpg or .wsq extensions, but I cannot get this to work.
I tried things like this:
find . -type f -name '*_101_*' -o -not -name *.jpg -o -name *.wsq
but it doesn't work.
What am I doing wrong?

Your attempt does "matches _101_, or does not end in .jpg, or does not end in .wsq". That'll match every single file, based on the two extensions alone, as a file can only have one.
You have to group differently:
find . -type f -name '*_101_*' -not -name '*.jpg' -not -name '*.wsq'
This applies all rules (logical AND is implied).
You also should quote the parameters to -name, or they might be expanded by the shell instead of find.

You need to use parenthesis (or #Benjamin's solution)
otherwise a or not b or c is evaluated as (a or not b) or c.
And you need and instead of or to filter only files that satisfy both conditions (pass both tests). a and not (b or c)
find -name '*_101_*' -not \( -name '*.jpg' -o -name '*.wsq' \)

Related

Linux find -type f ignored

I'm creating a cron job, that will find all *.log* files (it will be used to remove them later, when it works).
The find command looks like this:
find /data/dg \( -path /data/dg/kf/data -o -path /data/dg/pg/data \) -prune -o -name "*.log*" -type f
And it should find all files with name ".log" that are not in directories /data/dg/kf/data and /data/dg/pg/data
However the output this command gives contains also the directories.
...
/data/dg/kf/log/controller.log.2019-09-08-22
/data/dg/kf/log/server.log.2019-09-09-07
/data/dg/kf/data
/data/dg/pg/log/postgresql-2019-09-27_000000.log
/data/dg/pg/log/postgresql-2019-09-27_100859.log
/data/dg/pg/log/postgresql-2019-09-27_102411.log
/data/dg/pg/data
/data/dg/sim/log/sim_2019-09-27-11.0.log
/data/dg/sim/log/sim_2019-09-27-12.0.log
...
It seems that -type f doesn't work. What's wrong?
put -type f right after /data/dg
find /data/dg -type f -not -path "/data/dg/kf/data*" -not -path "/data/dg/pg/data*" -name "*.log*"

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!
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.

Find all files contained into directory named

I would like to recursively find all files contained into a directory that has name “name1” or name “name2”
for instance:
structure/of/dir/name1/file1.a
structure/of/dir/name1/file2.b
structure/of/dir/name1/file3.c
structure/of/dir/name1/subfolder/file1s.a
structure/of/dir/name1/subfolder/file2s.b
structure/of/dir/name2/file1.a
structure/of/dir/name2/file2.b
structure/of/dir/name2/file3.c
structure/of/dir/name2/subfolder/file1s.a
structure/of/dir/name2/subfolder/file2s.b
structure/of/dir/name3/name1.a ←this should not show up in the result
structure/of/dir/name3/name2.a ←this should not show up in the result
so when I start my magic command the expected output should be this and only this:
structure/of/dir/name1/file1.a
structure/of/dir/name1/file2.b
structure/of/dir/name1/file3.c
structure/of/dir/name2/file1.a
structure/of/dir/name2/file2.b
structure/of/dir/name2/file3.c
I scripted something but it does not work because it search within the files and not only folder names:
for entry in $(find $SEARCH_DIR -type f | grep 'name1\|name2');
do
echo "FileName: $(basename $entry)"
done
If you can use the -regex option, avoiding subfolders with [^/]:
~$ find . -type f -regex ".*name1/[^/]*" -o -regex ".*name2/[^/]*"
./structure/of/dir/name2/file1.a
./structure/of/dir/name2/file3.c
./structure/of/dir/name2/subfolder
./structure/of/dir/name2/file2.b
./structure/of/dir/name1/file1.a
./structure/of/dir/name1/file3.c
./structure/of/dir/name1/file2.b
I'd use -path and -prune for this, since it's standard (unlike -regex which is GNU specific).
find . \( -path "*/name1/*" -o -path "*/name2/*" \) -prune -type f -print
But more importantly, never do for file in $(find...). Use finds -exec or a while read loop instead, depending on what you really need to with the matching files. See UsingFind and BashFAQ 20 for more on how to handle find safely.

Find especific directory and ignore other

I need to find all the iplanets on one server and I was thinking to use this command:
find / type d -name https-* | uniq
But at the same time I need to ignore some directories/file. I've been trying to use !, but it not always work. I have a command like this:
find / type d -name https-* ! -name https-admserv* ! -name conf_bk* ! -name alias* ! -name *db* ! -name ClassCache* | uniq
I need to ignore all that. The directories admserv, conf_bk, alias and tmp and the files *.db*
Basically I need find this:
/opt/mw/iplanet/https-daniel.com
/opt/https-daniel1.com
/apps/https-daniel2.com
I only need to find the directory name. How can I ignore all the other stuff?
Use -prune to keep from recursing into directories:
find / \( -type d \( -name 'https-admserv*' -o -name 'conf_bk*' -o -name 'alias*' -o -name 'tmp' \) -prune -o -type d -name 'https-*' -print
There's no need to ignore any files. You're only selecting https-* directories, so everything else is ignored.
And there's no need to pipe to uniq, since find never produces duplicates.

Find command ignore directory

I am trying to find all files ending in .jar, but it is picking up folders that ends in .jar which is something I do not want.
My command so far
find . -name ".*jar"
I need it so it ignores directories ending in .jar
Additional request.
I now need to ignore a specific folder when looking, is this possible?
Thanks.
just add -type f:
find . -name "*.jar" -type f
Others have already shown, how to pick up files named ending in .jar. As an answer to your comment "How to ignore a specific folder". You use -prune for that
find . -name 'specific/folder' -type d -prune -o -type f -name '*.jar'
that's what you want
find . -type f -name "*.jar"
see man page:
-type Type
Evaluates to the value True if the Type variable specifies one of the following values:
b
Block special file
c
Character special file
d
Directory
f
Plain file
l
Symbolic link
p
FIFO (a named pipe)
s
Socket

Resources