With GNU find:
find /music -type d -execdir test -d {}/{} \; -printFor each file of the type directory test will be run. The trick is in how -execdir differs from -exec: for a directory named something, test will be run in its parent directory and {} will be expanded to ./something. In effect the actual inside command will be test -d ./something/./something, equivalent to test -d something/something. Then we use the fact that -execdir … \; (like -exec … \;) is not only an action, it is a test that succeeds iff the exit status from whatever it runs is 0. test -d checks if the given pathname is the name of a directory, it reports success via its exit status.
This way -print will be evaluated only (almost only, see just below) for directories containing directories of the same name.
Notes:
test -dsucceeds also for a symlink to a directory. You can add! -execdir test -L {}/{} \;(before-print) to ignore cases wheresomething/somethingis a symlink.In general remember that
{}expands to whatfindconsiders the pathname of the currently processed file, not necessarily to what a command likerealpath …would print. Similarly-nametests whatfindconsiders the name, not necessarily to whatbasename "$(realpath …)"would print. E.g. if the starting point is/musicthen at some point our command will test./music/./musicinside/music/.., so effectively/music/musicwhich may or may not be an existing directory and the test is conclusive, which is fine. But:If the (or a) starting point was
.(or e.g./music/.!), then it would be reported becausetest -dwould test./././.which is a directory for sure (regardless of the working directory oftest), so the test is not conclusive.! -name .is a test that "fixes" this, i.e. it unconditionally excludes.. But now we can miss a directory: if the current working directory is/musicand/music/musicexists, we won't detect it.In general passing
.as a starting point tofindis quite common. In our case, if you need to start at., considerfind "$PWD" …instead.Similarly if the (or a) starting point was
..(or e.g./music/artist/..), then it would be reported becausetest -dwould test./.././..which is a directory for sure (regardless of the working directory oftest).! -name ..is a test that "fixes" this, but again we can miss one specific directory. In general passing..as a starting point tofindis uncommon, still possible.
If the starting point is
/musicthen there will be no problem.The successful detection occurs when
findprocesses the upper (closer to/) directory from eachsomething/somethingpair, not the lower one. This has the following consequences:Our command will print paths like
/music/foo/bar/something(as opposed to/music/foo/bar/something/something)For
-mindepthor-maxdepth(if you decide to use them), the depth of the upper directory matters.If you want to automate doing something to one of the directories of the pair:
- work with the upper one by passing
{}after-execor-execdir; - but the easiest way to address the lower one is to use
{}/{}after-execdirlike we did; in general this will not work after-exec.
- work with the upper one by passing