Using bash
release 4 or newer. On macOS, this may be installed via the Homebrew package manager, as the default bash
is too old.
# Make glob patterns disappear rather than remain unexpanded
# if the don't match (nullglob).
# Make glob patterns also match hidden names (dotglob).
shopt -s nullglob dotglob
# Create an associative array that hold the number of times
# a directory's name has been seen (the basename of the directory's
# pathname is the key into this array).
declare -A count
# Set the positional parameters ($1, $2, etc.) to the pathnames
# of the directories that we're interested in.
set -- Top_Dir/*/*/
# Loop over out directory paths,
# and count how many times each basename occurs.
for dirpath do
name=$( basename "$dirpath" )
count["$name"]=$(( count["$name"] + 1 ))
done
# Loop over the directory paths again, but this time
# output each directory whose basename occurs more than once.
for dirpath do
name=$( basename "$dirpath" )
[[ ${count["$name"]} -gt 1 ]] && printf '%s\n' "$dirpath"
done
Testing:
$ tree -F
.
|-- Top_Dir/
| |-- Level_1_Dir/
| | |-- standard_cat/
| | |-- standard_dog/
| | `-- standard_snake/
| |-- Level_2_Dir/
| | |-- standard_cat/
| | |-- standard_moon/
| | `-- standard_sun/
| `-- Level_3_Dir/
| |-- standard_man/
| |-- standard_moon/
| `-- standard_woman/
`-- script
13 directories, 1 file
$ bash script
Top_Dir/Level_1_Dir/standard_cat/
Top_Dir/Level_2_Dir/standard_cat/
Top_Dir/Level_2_Dir/standard_moon/
Top_Dir/Level_3_Dir/standard_moon/
To support older bash
releases, you may choose to store the unique basenames of the directories and the counts of how many times each basename has been seen in two separate ordinary arrays. This requires a linear search in each loop:
shopt -s nullglob dotglob
set -- Top_Dir/*/*/
names=()
counts=()
for dirpath do
name=$( basename "$dirpath" )
found=false
for i in "${!names[@]}"; do
if [[ ${names[i]} == "$name" ]]; then
found=true
break
fi
done
if "$found"; then
counts[i]=$(( counts[i] + 1 ))
else
names+=( "$name" )
counts+=( 1 )
fi
done
for dirpath do
name=$( basename "$dirpath" )
for i in "${!names[@]}"; do
if [[ ${names[i]} == "$name" ]]; then
[[ ${counts[i]} -gt 1 ]] && printf '%s\n' "$dirpath"
break
fi
done
done