I have a less than beautiful solution for this.
In script form:
#!/bin/bash
# Echo whatever is passed to fail, and then exit with a status of 1
fail() {
echo >&2 "$@"
exit 1
}
# If the number of arguments are less or more than what
# we expect, throw help syntax and exit.
if [ $# -gt 2 ] || [ $# -lt 2 ]
then
fail "
$0 check for directories that only contain hidden listings
Usage: $0 <Directory to search from> <Depth to check>
"
fi
# Assign parameters
root_dir=$1
depth=$2
# Find a list of directories that contain files OR subdirectories
# that are hidden
readarray -t dirs < <(export LC_ALL=C
find "$root_dir" -mindepth "$depth" -maxdepth "$depth" \
-name ".*" \( -type d -o -type f \) -execdir pwd \; | sort -u
)
# Of the dirs we found, do any of them return any listings with a
# default ls execution? If so, that directory cannot only contain
# hidden listings.
final=()
for dir in "${dirs[@]}"
do
notExclusive="$(ls -- "$dir")"
if [ "$notExclusive" = "" ]
then
final+=("$dir")
fi
done
# The array final contains the directories who only contain hidden
# files/subdirectories.
printf '%s\n' "${final[@]}"
Basically we just find directories that contain hidden listings (at a depth of 2 as specified in question), load them into an array, and if ls
with no flags returns nothing, we can conclude that only hidden listings are contained in the directory, which meets our criteria.
To explain why you only need one invocation of find
per the comments on the OP. The command find
has operators for your basic logic, -a the default behavior when you join two expressions logical AND, ! as in a logical NOT, and -o as in logical OR.
This approach assumes directory paths don't contain newline characters, if they do readarray
will incorrectly separate each directory path.
Ugly 'one-liner':
readarray -t dirs < <(export LC_ALL=C; find ./Root_Dir -mindepth 2 -maxdepth 2 -name '.*' \( -type d -o -type f \) -execdir pwd \; | sort -u); final=(); for dir in "${dirs[@]}"; do notExclusive="$(ls -- "$dir")"; if [ "$notExclusive" = "" ]; then final+=("$dir"); fi; done; printf '%s\n' "${final[@]}"
.files
; Of these, which don't have non.files
?Dir_N
directory... if there was a hidden directory withinDir_N
and nothing else, that would be a match. It would not matter what is contained within that hidden directory.tree -aif -L 2 root_dir
then perhaps some cunning piece of AWK could do the job???