0

i want to exclude one directory from the find search tree. .aaa is a hidden sub-directory in the current directory. I want to exclude aaa_rc_bbb, xxx_rc_xxx and many more sub-directories containing rc in their names. But it still not ignoring and giving me results containing rc sub-directories. Its as if *rc* wildcard is not working.

find -L /students/projects/myname/ -name .aaa -prune -o -path */*/class_project/*/*/pikachu/*/*/*rc*/ -prune -o -path */*/class_project/*/*/pikachu/*/*/bambi/b‌​ambi.txt | head -n50 | xargs ls.

Also, i want find to search only in this path : */*/class_project/*/*/pikachu/*/*/bambi/b‌​ambi.txt

Please help me. Am i doing anything wrong?

2 Answers 2

3

The first issue is that you have unquoted globs (*). All those paths should be surrounded with single quotes, e.g. '*/*/class_project/*/*/pikachu/*/*/bambi/b‌​ambi.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/b‌​ambi.txt' \
  \) -prune \
  -o -print
6
  • @B Layer, I am not understanding find \( \( -name '*foo*' -o -name '*bar*' \) -a -prune \) -o \( -name baz -a -print \) Can you write the same thing in my expression, then i will understand. :-)
    – Pompy
    Dec 27, 2017 at 11:11
  • 1
    You're welcome. Just do yourself a favor and understand the answer rather than blindly copy the last part.
    – B Layer
    Dec 27, 2017 at 11:42
  • Yes, i understood with the notes you just provided, no need to write in my expression, you can delete it.
    – Pompy
    Dec 27, 2017 at 11:45
  • Great. I'll leave your example there since it illustrates the concepts (for others who read it.)
    – B Layer
    Dec 27, 2017 at 11:47
  • But my problem is not solved, my problem is that *rc* is not being read by bash. There are so many directories containing rc letter, i want to prune them all.
    – Pompy
    Dec 27, 2017 at 11:54
1

Your -path pattern ends with a slash. No pathname that find examines will ever end in a slash, so the pattern will never match anything.

To prune any directory called .aaa and any directory with rc in its name:

find -L /students/projects/myname \
    -type d '(' -name '.aaa' -o -name '*rc*' ')' -prune -o -print

To only look at the path */*/class_project/*/*/pikachu/*/*/bambi/b‌​ambi.txt:

find -L /students/projects/myname \
    -type d '(' -name '.aaa' -o -name '*rc*' ')' -prune -o \
    -path '*/*/class_project/*/*/pikachu/*/*/bambi/b‌​ambi.txt' -print

This assumes that bambi.txt is located in

/students/projects/myname/*/*/class_project/*/*/pikachu/*/*/bambi/b‌​ambi.txt

Note the quoting of the patterns in the find command. Without quotes, the shell would try to expand the patterns to lists of pathnames before calling find, possibly resulting in confusing find, or with some shells, an error.

1
  • Oh, I just edited that into the accepted answer before realising your answer already pointed it out. Jul 24, 2020 at 6:33

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .