You are making this far more complicated than needed. You don't seem to want to recurse into subdirectories, so all you need to find those directories that don't have a specific file is:
for dir in */; do [ ! -e "$dir"/"$filename" ] || printf '%s\n' "$dir"; done
And, to see which of those do have another file:
for dir in */; do
[ ! -e "$dir"/"$filename1" ] &&
[ -e "$dir"/"$filename2" ] &&
printf '%s\n' "$dir";
done
Or, in a slightly clearer syntax:
for dir in */; do
if [ ! -e "$dir"/"$filename1" ]; then
if [ -e "$dir"/"$filename2" ]; then
printf '%s\n' "$dir";
fi
fi
done
This is all done using the built-in tools of the shell. Specifically:
[
: this, and the accompanying ]
are synonyms for the test
builtin (see help [
or help test
if using an sh-style shell). They are ways of writing test operations in the shell.
-e
: this tests whether a file/directory etc exists. See help test
. The simple format is: [ -e file ]
which will return true if file
exists.
[ ! -e filename ]
: the !
simply inverses the test. So [ ! -e file ]
will be true if file
does not exist.
Taken together, this means the command above does:
## Iterate over every directory (dirs only because of the '/' in '*/')
## saving each of them in the variable $dir.
for dir in */; do
## If this $dir does not contain $filename1
if [ ! -e "$dir"/"$filename1" ]; then
## If this $dir does contain $filename2
if [ -e "$dir"/"$filename2" ]; then
## Print the directory name
printf '%s\n' "$dir";
fi
fi
done
To run this, of course, you need to first set $filename1
and $filename2
accordingly. For example:
filename1="unwantedFile"
filename2="wantedFile"