prune' option of 'find' in sh?

I don't quite understand the example given from the 'man find', can anyone give me some examples and explanations? Can I combine regular expression in it?


the more detailed question is like this: write a shell script, changeall, which has an interface like "changeall [-r|-R] "string1" "string2". It will find all files with an suffix of .h, .C, .cc, or .cpp and change all occurrences of "string1" to "string2". -r is option for staying in current dir only or including subdir's. NOTE: 1) for non-recursive case, 'ls' is NOT allowed, we could only use 'find' and 'sed'. 2) I tried 'find -depth' but it was NOT supported. That's why I was wondering if '-prune' could help, but didn't understand the example from 'man find'.


EDIT2: I was doing assignment, I didn't ask question in great details because I would like to finish it myself. Since I already done it and hand it in, now I can state the whole question. Also, I managed to finish the assignment without using -prune, but would like to learn it anyway.


The thing I'd found confusing about about -prune is that it's an action (like -print ), not a test (like -name ). It alters the "to-do" list, but always returns true.

The general pattern for using -prune is this:

find [path] [conditions to prune] -prune -o 
                                   [your usual conditions] [actions to perform]

You pretty much always want the the -o immediately after -prune , because that first part of the test (up to including -prune ) will return false for the stuff you actually want (ie: the stuff you don't want to prune out).

Here's an example:

find . -name .snapshot -prune -o -name '*.foo' -print

This will find the "*.foo" files that aren't under ".snapshot" directories. In this example, -name .snapshot is the "tests for stuff you want to prune", and -name '*.foo' -print is the "stuff you'd normally put after the path".

Important notes :

  • If all you want to do is print the results you might be used to leaving out the -print action. You generally don't want to do that when using -prune .

    The default behavior of find is to "and" the entire expression with the -print action if there are no actions other than -prune (ironically) at the end. That means that writing this:

    find . -name .snapshot -prune -o -name '*.foo'              # DON'T DO THIS
    

    is equivalent to writing this:

    find . ( -name .snapshot -prune -o -name '*.foo' ) -print # DON'T DO THIS
    

    which means that it'll also print out the name of the directory you're pruning, which usually isn't what you want. Instead it's better to explicitly specify the -print action if that's what you want:

    find . -name .snapshot -prune -o -name '*.foo' -print       # DO THIS
    
  • If your "usual condition" happens to match files that also match your prune condition, those files will not be included in the output. The way to fix this is to add a -type d predicate to your prune condition.

    For example, suppose we wanted to prune out any directory that started with .git (this is admittedly somewhat contrived -- normally you only need to remove thing named exactly .git ), but other than that wanted to see all files, including files like .gitignore . You might try this:

    find . -name '.git*' -prune -o -type f -print               # DON'T DO THIS
    

    This would not include .gitignore in the output. Here's the fixed version:

    find . -type d -name '.git*' -prune -o -type f -print       # DO THIS
    
  • Extra tip: if you're using the GNU version of find , the texinfo page for find has a more detailed explanation than its manpage (as is true for most GNU utilities).


    Beware that -prune does not prevent descending into any directory as some have said. It prevents descending into directories that match the test it's applied to. Perhaps some examples will help (see the bottom for a regex example). Sorry for this being so lengthy.

    $ find . -printf "%y %pn"    # print the file type the first time FYI
    d .
    f ./test
    d ./dir1
    d ./dir1/test
    f ./dir1/test/file
    f ./dir1/test/test
    d ./dir1/scripts
    f ./dir1/scripts/myscript.pl
    f ./dir1/scripts/myscript.sh
    f ./dir1/scripts/myscript.py
    d ./dir2
    d ./dir2/test
    f ./dir2/test/file
    f ./dir2/test/myscript.pl
    f ./dir2/test/myscript.sh
    
    $ find . -name test
    ./test
    ./dir1/test
    ./dir1/test/test
    ./dir2/test
    
    $ find . -prune
    .
    
    $ find . -name test -prune
    ./test
    ./dir1/test
    ./dir2/test
    
    $ find . -name test -prune -o -print
    .
    ./dir1
    ./dir1/scripts
    ./dir1/scripts/myscript.pl
    ./dir1/scripts/myscript.sh
    ./dir1/scripts/myscript.py
    ./dir2
    
    $ find . -regex ".*/my.*p.$"
    ./dir1/scripts/myscript.pl
    ./dir1/scripts/myscript.py
    ./dir2/test/myscript.pl
    
    $ find . -name test -prune -regex ".*/my.*p.$"
    (no results)
    
    $ find . -name test -prune -o -regex ".*/my.*p.$"
    ./test
    ./dir1/test
    ./dir1/scripts/myscript.pl
    ./dir1/scripts/myscript.py
    ./dir2/test
    
    $ find . -regex ".*/my.*p.$" -a -not -regex ".*test.*"
    ./dir1/scripts/myscript.pl
    ./dir1/scripts/myscript.py
    
    $ find . -not -regex ".*test.*"                   .
    ./dir1
    ./dir1/scripts
    ./dir1/scripts/myscript.pl
    ./dir1/scripts/myscript.sh
    ./dir1/scripts/myscript.py
    ./dir2
    

    Normally the native way we do things in linux and the way we think is from left to right.
    So you would go and write what you are looking for first:

    find / -name "*.php"
    

    Then you probably hit enter and realize you are getting too many files from directories you wish not to. Let's exclude /media to avoid searching your mounted drives.
    You should now just APPEND the following to the previous command:

    -print -o -path '/media' -prune
    

    so the final command is:

    find / -name "*.php" -print -o -path '/media' -prune
    

    ...............|<--- Include --->|....................|<---------- Exclude --------->|

    I think this structure is much easier and correlates to the right approach

    链接地址: http://www.djcxy.com/p/78134.html

    上一篇: 整个目录树的结尾(Git)

    下一篇: 修剪'选择'找到'sh?