By default, find
always returns true (0), whether it finds a matching file or not.
However, using the -exec
predicate to run /bin/false
on matching file(s), you can get it to return false (1) if it finds one or more matches. Testing the negation (!
) of that will be true if found, false otherwise.
For example:
# does the lock file exist?
if ! find "$MAINTENANCE_LOCK/testLOCK" -mtime -1 -exec false {} + ; then
# are there any .control files?
if ! find "$PATH_TO_TRIGGER_FILES" -name '*.control' -exec false {} + ; then
test_log_msg "test_SYSTEM" $NOTICE "Valid Maintenance Lock file found, test actions blocked." "status"
test_log_email " " " " " " "test Actions were blocked because an testLOCK file less than 24hrs old is in place." " "
else
test_log_msg "test_SYSTEM" $NOTICE "Valid Maintenance Lock file in place." "status"
exit
fi
fi
If you do this a lot, or just want your script to be more-readable/self-documenting, you could wrap it in a function:
file_exists () {
# The args to this function are passed directly to find,
# so anything that works with find will work here.
# And anything that breaks find will break this function too.
# Also, you probably don't want to use any find arguments that
# produce any output.
if ! find "$@" -exec false {} + ; then
# one or more matching files were found, return true
return 0
else
# nothing found, return false
return 1
fi
}
if file_exists "$MAINTENANCE_LOCK/testLOCK" -mtime -1 ; then
if file_exists "$PATH_TO_TRIGGER_FILES" -name '*.control' ; then
...
else
...
fi
fi
Note that /bin/false
completely ignores its argument(s), it just returns an exit code of false (1) no matter how many args it has...so this is useful if you only need to test for existence but NOT useful if you need to count the number of matching files. If you needed to do that, you could do something like (with GNU find or any other find that supports -printf
):
if [ "$(find . -mtime -1 -printf 1 | wc -c)" -gt 10 ] ; then
: do something here
fi
This prints a single character for each file found (it doesn't matter which character is printed - I'm using "1" here, but it would work the same for "." or "x" or any other char), and then counts them with wc -c
. If there are more than 10, then the if
test evaluates as true.
For a non-GNU find
without -printf
that supports the (also non-POSIX, but still quite common) -print0
option, you could use:
if [ "$(find . -mtime -1 -print0 | awk -v RS='\0' 'END{print NR}')" -gt 10 ] ; then
: do something here
fi
This version uses awk
to print the number of NUL-separated records (i.e. the number of matching files) in find
's output.
If you are absolutely certain that none of the file or directory names will ever contain a newline (\n
) character, then you could just use the POSIX standard -print
instead of -print0
(and pipe into wc -l
) - but that is never something you can rely on because you can never really be absolutely certain that such a filename will never exist at some point in the future. i.e. at best, it might work now but could fail tomorrow, or next year.
if [ -n "$(find "$MAINTENANCE_LOCK/testLOCK" -mtime -1)" ] ; then
... Puttingfind
directly inside[...]
doesn't really make any sense. – frabjous Oct 18 '22 at 22:05if [ -f "$PATH_TO_TRIGGER_FILES/*.control" ]
probably isn't what you want either, unless the file literally should have an asterisk in its name. You could do something similar to the other conditional.if [ -n "$(find "$PATH_TO_TRIGGER_FILES" -name '*.control')" ] ; then
– frabjous Oct 18 '22 at 22:12