TransWikia.com

find's prune's -path is not taking wildcards

Unix & Linux Asked by Pompy on December 8, 2020

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

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.

Answered by Kusalananda on December 8, 2020

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

Answered by B Layer on December 8, 2020

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP