The first issue is that you have unquoted globs (*
). All those paths should be surrounded with single quotes, e.g. '*/*/class_project/*/*/pikachu/*/*/bambi/bambi.txt'
. This prevents the shell from expanding the wildcards before they get passed to find
.
Next, you need the -prune
sub-expression to occur before the main search sub-expression. BTW, you can combine all the names into a compound expression with a single -prune
like this:
find \( \( -name '*foo*' -o -name '*bar*' \) -a -prune \) -o \( -name baz -a -print \)
This means I want to find files named baz
while excluding any files/directories containing foo
or bar
in their names.
Some notes:
- I'm being liberal with the
-a
(AND) operator and the parentheses so there is no ambiguity.
- Parentheses, which act to change precedence just like with most other expression types, are escaped with
\
so they are not interpreted by the shell before being passed to find
.
- I'm using two
-name
tests but any other tests (e.g. -path
) can be in the first nested set of parentheses. Any file/dir matching any of the tests will be pruned and thus not applied to the next tests (in the last set of parens).
- It's a good idea to be explicit with the
-print
action to distinguish it from the -prune
part.
For clarity let's rewrite this in a more common expression style:
((name=='*foo*' OR name=='*bar*') AND prune) OR (name==bar AND print)
or even
if (name=='*foo*' OR name=='*bar*')
prune
else if (name==bar)
print
fi
Now given normal precedence rules and that the default boolean operator is -a
we can reduce the example down to:
find \( -name '*foo*' -o -name '*bar*' \) -prune -o -name baz -print
Turning to your command, the paths that find
constructs for the files it discovers will never end in /
characters, so -path '*/*/class_project/*/*/pikachu/*/*/*rc*/'
could never possibly match. You'd need to drop that trailing /
and possibly add a -type d
if you want to restrict to files of type directory.
Also note that */*
as a pattern matches on any string that contains a /
, that also includes foo/bar/baz
. Here, your paths all start with /students/projects/myname/
so the /
in */*
is redundant as we know already that that /
will be there.
If I'm reading your intent correctly you don't have any tests for the second sub-expression, i.e. if a file doesn't get pruned you want to print it. So that leads to
find -L /students/projects/myname/ \
\( \
-name .aaa \
-o -path '*/class_project/*/*/pikachu/*/*/*rc*' \
-o -path '*/class_project/*/*/pikachu/*/*/bambi/bambi.txt' \
\) -prune \
-o -print