16

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?

5
  • 1
    I don't think find directly supports it. You can do something like find ... -print0 | grep -qz ., perhaps, if your grep supports it.
    – muru
    Apr 23, 2015 at 22:50
  • My grep is gnu grep so it supports this nice idea. Unfortunately, I also need the find output to be piped somewhere and I cannot replace the pipe with -exec.
    – XZS
    Apr 23, 2015 at 22:56
  • I'm making something.
    – Aloha
    Apr 23, 2015 at 22:57
  • 1
    @XZS you can skip the -q, then grep will simply pass through the data, while still breaking the pipeline and reporting a failure if nothing comes through.
    – muru
    Apr 23, 2015 at 23:02
  • @muru A do-nothing grep guarding the pipe, very elegant. Turn this into an answer and it will be accepted.
    – XZS
    Apr 23, 2015 at 23:19

3 Answers 3

11

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.

3
  • Grep's -z is a GNU extension. Do you have something for more Posixy?
    – user56041
    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_STATUS or something similar), then it probably has a read which can do null-delimited input; then you can read a single line, fail if empty; or print it back out and cat the rest. (Assuming you want to pass on the data to something else, otherwise you can probably do find ... -exec echo foo {} \+ | grep -q foo.)
    – muru
    Oct 22, 2017 at 14:17
  • Is -z just to make sure strange characters like \r are preserved? If piping through grep isn't desired, or there are no weird filenames, then is grep -z needed?
    – mwfearnley
    Sep 29, 2022 at 12:38
4

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

0

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à".

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .