When find is invoked to find nothing, it still exits with code 0. Is there a way to make it return an exit code indicating failure when no file was found?
3 Answers
If your grep supports reading NUL-delimited lines (like GNU grep with -z), you can use it to test if anything was output by find:
find /some/path -print0 | grep -qz .
To pipe the data to another command, you can remove the -q option, letting grep pass on the data unaltered while still reporting an error if nothing came through:
find /some/path -print0 | grep -z . | ...
Specifically, ${PIPESTATUS[1]} in bash should hold the exit status of grep.
If your find doesn't support -print0, the use grep without -z and hope that newlines in filenames don't cause problems:
find ... | grep '^' | ...
In this case, using ^ instead of . might be safer. If output has consecutive newlines, ^ will pass them by, but . won't.
-
Grep's
-zis a GNU extension. Do you have something for more Posixy?user56041– user560412017-10-21 09:11:36 +00:00Commented Oct 21, 2017 at 9:11 -
@jww unlikely, since with pure POSIX, I don't think you can detect a failure in the middle of a shell pipe. If you have a shell which can do that (via
PIPE_STATUSor something similar), then it probably has areadwhich can do null-delimited input; then you can read a single line, fail if empty; or print it back out andcatthe rest. (Assuming you want to pass on the data to something else, otherwise you can probably dofind ... -exec echo foo {} \+ | grep -q foo.)muru– muru2017-10-22 14:17:27 +00:00Commented Oct 22, 2017 at 14:17 -
Is
-zjust to make sure strange characters like\rare preserved? If piping through grep isn't desired, or there are no weird filenames, then isgrep -zneeded?mwfearnley– mwfearnley2022-09-29 12:38:24 +00:00Commented Sep 29, 2022 at 12:38
You ask specifically for a return code... which I don't see in options. But this is how I solved it (because grep -z is not on Mac port):
Gives code 0 if 1 line was found
test 1 == `find */.kitchen/ -name private_key | wc -l`
So...
if [ 0 == `find */.kitchen/ -name my-file.txt | wc -l` ] ; then
echo "Nothing found"; exit;
fi
Also, as a generic solution, this might be useful:
Check if pipe is empty and run a command on the data if it isn't
I am very late to this question, but I just found an elegant answer :-)
find . -type d -empty -and -not -name . -print -exec rmdir {} + | \
awk '{print} END {if (NR == 0) {exit(1)}}'
find here looks for empty directories in the current directory,
removes the empty directories,
prints the name of removed directories to the pipe,
awk prints the output of find and if no output is found NR == 0, bails out with an error code.
This means I can now iteratively remove empty directories:
while find . -type d -empty -and -not -name . -print -exec rmdir {} + | \
awk '{print} END {if (NR == 0) {exit(1)}}'; \
do echo; done
Replace "my" find parameters with yours, keep the awk part either as is or without the {print} if you do not want to see the output of find in the terminal, and "voilà".
finddirectly supports it. You can do something likefind ... -print0 | grep -qz ., perhaps, if yourgrepsupports it.-exec.-q, thengrepwill simply pass through the data, while still breaking the pipeline and reporting a failure if nothing comes through.