5

How can I prevent find from returning the directory I use as the root to start searching from in the results? e.g.:

$ find targetDir -name 'target*'
targetDir/target1
targetDir/target2
targetDir/subDir/target3

instead of:

$ find targetDir -name 'target*'
targetDir
targetDir/target1
targetDir/target2
targetDir/subDir/target3
0

6 Answers 6

10

Use mindepth (if your find implementation has this option):

$ find targetDir -mindepth 1 -name 'target*'

From man find:

   -mindepth levels
          Do  not apply any tests or actions at levels less than levels (a
          non-negative integer).  -mindepth  1  means  process  all  files
          except the command line arguments.
2

With GNU, BSD or BusyBox find (i.e. on Linux, *BSD or Cygwin):

find targetDir -mindepth 1 -name 'target*'

If you only have POSIX find (e.g. on Solaris or MINIX), the easy way is to change to the toplevel directory first. Then the location of the search has the unique name . which you can exclude.

( cd targetDir && find . -name . -o -name 'target*' -print )

If you really need to run from another directory, you can exclude directories called targetDir, but that will also exclude things like targetDir/something/targetDir.

Alternatively, you can make the shell do the work for you. Use a set of patterns to match all files in a directory. A downside is that you'll get an error message from find if one of the patterns doesn't match.

find targetDir/..?* targetDir/.[!.]* targetDir/* -name 'target*'

If you know that there are no dot files in the directory and that the directory is not empty, you can go with just *.

find targetDir/* -name 'target*'
1

A simple trick is to do like this:

$ find targetDir/* -name 'target*'

This will effectively exclude the root dir (targetDir) from the search.

1
  • 2
    Be aware that this will ignore all hidden files/directories in targetDir.
    – michas
    Jan 3, 2014 at 13:29
1

An equivalent to GNU's -mindepth on systems where find doesn't support it is to use -path with a pattern that requires file paths to contain a certain amount of / characters.

find targetDir -mindepth 1 -name 'target*'

becomes:

find targetDir -path '*/*' -name 'target*'

or:

find targetDir -path 'targetDir/*' -name 'target*'

And

find path/to/targetDir -mindepth 1 -name 'target*'

becomes

find path/to/targetDir -path '*/*/*/*' -name 'target*'

or:

find path/to/targetDir -path 'path/to/targetDir/*' -name 'target*'

It becomes more awkward if passing more than one dir to find:

find targetDir other/targetDir -mindepth 1 -name 'target*'

Would become:

find targetDir other/targetDir \
  '(' -path 'targetDir/*' -o 'other/targetDir/*' ')' \
  -name 'target*'

Another approach is to append a / to the starting directories and use ! -path '*/' to filter them out:

find targetDir/ other/targetDir/ ! -path '*/' -name 'target*'

Beware that it changes the behaviour if those targetDirs are symlinks in which case they will be followed as if you had passed the -H option. You might also find that with some find implementations, matching files are printed as targetDir//targetfile instead of targetDir/targetfile

In all those approaches beware that with some find implementations including GNU find on GNU systems, * in -name or -path doesn't match on byte sequences that don't form valid characters in the locale which would throw things off here. Prepending LC_ALL=C to those commands would work around the issue.

Appending /. and filter out with ! -name . (not even needed if the search criteria is just -name 'target*' which . doesn't match) would not have the issue:

find targetDir/. other/targetDir/. ! -name . -more-criteria

But means matching file paths are printed as targetDir/./targetFile with all find implementations. You can fix that cosmetic issue by piping the output to sed 's|/\./|/|' though.

0
0

It might be easier to specify what you really want instead of trying to ignore things you don't want. For example -type f will return only regular files, and will therefore not output the start directory.

But this really depends on what you are after, and why you want to get rid of the base dir.

0

yet another way: [just for the sake of providing one, in the "timtowtdi" idea]

( cd targetDir && find . -name 'target*' ) | sed -e 's#^./#targetDir/#'

of as a (more flexible)function:

findin () { 
    targetdir="$1" ; target="$2" 
    ( cd "${targetdir}" && find . -name "${target}" ) | sed -e "s#^./#${targetdir}/#"
}

findin "targetDir" 'target*'

You must log in to answer this question.

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