shin
shin

Reputation: 351

Check if directory contains only hidden files and no directories

I'm trying to put a third check whether the directory contains only hidden files:

if [ ! "$(ls -A "$dir")" ]; then
  echo "Specified directory is empty"
  exit 1
elif [[ -z "$(find "$dir" -maxdepth 1 -type f)" ]]; then
  echo "Specified directory contains only subdirectories and no files"
  exit 1
elif [[ -z "$(find "$dir" -maxdepth 1 -type f | grep -v '"$dir"/.*')" ]]; then
  echo "Specified directory contains only hidden files"
  exit 1
fi

The third check is what is not working. I tried getting a list of all files that don't match '.*' and checking if it's empty with -z, but it always tests true. Do you have an idea?

Upvotes: 1

Views: 370

Answers (1)

tripleee
tripleee

Reputation: 189397

Generally don't use ls in scripts.

Assuming you have the default values for nullglob etc,

files=(./*)
if [[ "${files[@]}" = './*' ]]; then
  echo "Specified directory is empty" >&2
  exit 1
fi
dirs=(./*/)
if [[ "${#dirs[@]}" = "${#files[@]}" ]]; then
  echo "Specified directory contains only subdirectories and no files" >&2
  exit 1
fi
hidden=(./.*)
if [[ "${#hidden[@]}" = "${#files[@]}" ]]; then
  echo "Specified directory contains only hidden files" >&2
  exit 1
fi

There is an obvious race condition here, in that another process could add a new hidden file after files gets assigned, but before hidden gets assigned, for example.

The use of arrays makes this Bash-only; this should be obvious, but many beginners are confused about the difference between sh and bash.

The immediate error in your attempt is that '"$dir"/.*' is in single quotes, and so gets interpreted verbatim (and even if you fixed the quoting, . in a regex matches any character, not a literal dot). But more broadly, it seems excessive to use find when the shell itself can tell you what files you have.

Upvotes: 1

Related Questions