39

I want to write a bash script which will use a list of all the directories containing specific files. I can use find to echo the path of each and every matching file. I only want to list the path to the directory containing at least one matching file.

For example, given the following directory structure:

dir1/
    matches1
    matches2
dir2/
    no-match

The command (looking for 'matches*') will only output the path to dir1.

As extra background, I'm using this to find each directory which contains a Java .class file.

Grundlefleck
  • 124,925
  • 25
  • 94
  • 111

7 Answers7

75
find . -name '*.class' -printf '%h\n' | sort -u

From man find:

-printf format

%h Leading directories of file’s name (all but the last element). If the file name contains no slashes (since it is in the current directory) the %h specifier expands to ".".

GaZ
  • 2,346
  • 23
  • 46
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • 5
    Nice, thanks. For copy pasters: `find` also needs a directory after `find`, e.g. `find . -name '*.class' -printf '%h\n' | sort -u` to search from the current directory – Xiao Sep 25 '15 at 00:16
35

On OS X and FreeBSD, with a find that lacks the -printf option, this will work:

find . -name *.class -print0 | xargs -0 -n1 dirname | sort --unique

The -n1 in xargs sets to 1 the maximum number of arguments taken from standard input for each invocation of dirname

Community
  • 1
  • 1
xverges
  • 4,608
  • 1
  • 39
  • 60
  • 4
    On OSX, you can install gnu find with homebrew: `brew install findutils` and use it with: `gfind . -name '*.class' -printf '%h\n'` – Xiao Sep 25 '15 at 00:14
7

GNU find

find /root_path -type f -iname "*.class" -printf "%h\n" | sort -u
ghostdog74
  • 327,991
  • 56
  • 259
  • 343
3

Ok, i come way too late, but you also could do it without find, to answer specifically to "matching file with Bash" (or at least a POSIX shell).

ls */*.class | while read; do
  echo ${REPLY%/*}
done | sort -u

The ${VARNAME%/*} will strip everything after the last / (if you wanted to strip everything after the first, it would have been ${VARNAME%%/*}).

Regards.

bufh
  • 3,153
  • 31
  • 36
1
find / -name *.class -printf '%h\n' | sort --unique
Jim
  • 321
  • 1
  • 2
  • 6
1

Far too late, but this might be helpful to future readers: I personally find it more helpful to have the list of folders printed into a file, rather than to Terminal (on a Mac). For that, you can simply output the paths to a file, e.g. folders.txt, by using:

find . -name *.sql -print0 | xargs -0 -n1 dirname | sort --unique > folders.txt

davidqshull
  • 126
  • 1
  • 5
1

How about this?

find dirs/ -name '*.class' -exec dirname '{}' \; | awk '!seen[$0]++'

For the awk command, see #43 on this list

smac89
  • 39,374
  • 15
  • 132
  • 179