1

I'm trying to find/extract directories based on an expression that applies to the file path. For example, I used the command:

find . -type d -links 2

To get a list of directories that looks something like this:

./foo/ABC/W
./foo/ABC/X
./foo/ABC/Y
./foo/ABC/Z
./foo/BCD/W
./foo/BCD/X
./foo/BCD/Y
./foo/BCD/Z
./foo/CDE/W
./foo/CDE/X
./foo/CDE/Y
./foo/CDE/Z
./bar/CDE/V
./bar/CDE/Q
./bar/BCD/V
./bar/BCD/Q
./bar/ABC/V
./bar/ABC/Q

I'm wondering how to take this list, and extract only filepaths containing say, "CDE" in them:

./foo/CDE/W
./foo/CDE/X
./foo/CDE/Y
./foo/CDE/Z
./bar/CDE/V
./bar/CDE/Q

This is what I've tried so far, which outputs nothing when I try it:

find . -type d -links 2 -name "CDE" -print
bactro
  • 25
  • 3
  • Yes, it's not working however. It outputs nothing when I try it. – bactro Jul 21 '20 at 18:54
  • I don't think that solution works for me since it doesn't print subdirectories. I need to have subdirectories printed out as well (which is why I used `-links 2`), I'm passing this to -exec to copy files into each subdirectory. – bactro Jul 21 '20 at 19:02
  • (1) `-print` is the *default* action, but I wouldn’t call it redundant.  Leaving it off will sometimes cause a command to fail; see  [`find` with multiple `-name` and `-exec` executes only the last matches of `-name`](https://unix.stackexchange.com/q/102191/80216), [Operator precedence in a find command?](https://unix.stackexchange.com/q/276574/80216), [find: Why is the `-a` operator not commutative in combination with `-print`?](https://unix.stackexchange.com/q/152941/80216), and others.  So don’t just forget that `-print` exists; you may need it sometimes.  … (Cont’d) – G-Man Says 'Reinstate Monica' Jul 22 '20 at 00:49
  • (Cont’d) … (2) `-type d` will find all directories at all levels, including subdirectories. [As mentioned by Quasímodo](https://unix.stackexchange.com/q/599613/80216#599665), *on a proper Unix system, using a standard Unixy filesystem,* `-type d -links 2` will find only directories ***that have no subdirectories**.* This does not work on Cygwin, and might not work on WSL (Windows Subsystem for Linux), Ubuntu on Windows, Unix/Linux using a FAT disk or a file server like NetApp, etc. – G-Man Says 'Reinstate Monica' Jul 22 '20 at 00:49
  • See also [Find path that has specific sub directory](https://unix.stackexchange.com/q/342392/80216) and [Further questions about -path for find](https://unix.stackexchange.com/q/200344/80216). – G-Man Says 'Reinstate Monica' Jul 22 '20 at 00:50

2 Answers2

1
$ find . -type d -links 2 -path '*CDE*'
./foo/CDE/X
./foo/CDE/Z
./foo/CDE/W
./foo/CDE/Y
./bar/CDE/Q
./bar/CDE/V

Or use

find . -type d -links 2 -path '*/CDE/*'

if you know CDE is the name of a subdirectory somewhere in the middle of the paths you're looking for.

Freddy
  • 25,172
  • 1
  • 21
  • 60
0
find . -type d -links 2 -name "CDE" -print

matches directories whose basename is exactly CDE (because of -name CDE) and that have no child directories (because of -links 2).

The basename of a file is just the bit after the last / of its path. For instance, the basename of ./foo/CDE/W is W. From this you see that none of the directories matches both conditions.

You are after

find . -type d -links 2 -path '*/CDE/*'

The -path pattern option is true if

the current pathname matches pattern using the pattern matching notation described in Pattern Matching Notation.

In the "Pattern Matching Notation", the asterisk matches any string.

As a last note, -print is used by default unless -ok or -exec are present, so you can drop it.

Quasímodo
  • 18,625
  • 3
  • 35
  • 72