26

I want to run the command

find some/path -exec program \{} \; 

but I want the find command to quit as soon as the command

program \{}

fails on any of the files found.

Is there a simple way of doing this?

Benjamin Loison
  • 3,782
  • 4
  • 16
  • 33
FORTRAN
  • 567
  • 1
  • 6
  • 13
  • Related: http://unix.stackexchange.com/questions/62880/how-to-stop-the-find-command-after-first-match – kojiro Feb 14 '13 at 12:25

5 Answers5

14

I think it is not possible to achieve what you want, only with find -exec.

The closest alternative would be to do pipe find to xargs, like this:

find some/path -print0 | xargs -0 program

or

find some/path -print0 | xargs -0L1 program

This will quit if program terminates with a non-zero exit status

  • the print0 is used so that files with newlines in their names can be handled
  • -0 is necessary when -print0 is used
  • the L1 tells xargs program to execute program with one argument at a time (default is to add all arguments in a single execution of program)

If you only have sane file names, you can simplify like this:

find some/path | xargs program

or

find some/path | xargs -L1 program

Finally, If program takes more than one argument, you can use -i combined with {}. E.g.

find some/path | xargs -i program param1 param2 {} param4
user000001
  • 32,226
  • 12
  • 81
  • 108
7

In addition to the other fine answers, GNU find (at least) has a -quit predicate:

find path -other -predicates \( -exec cmd {} \; -o -quit \)

The -quit predicate is certainly non-standard and does not exist in BSD find.

kojiro
  • 74,557
  • 19
  • 143
  • 201
  • 6
    This is close to what I need but I need to exit with a nonzero exit status if this fails (the second part of the predicate). – Lucas Oct 14 '16 at 18:21
2

Here is my example for a "build system", which stops after hitting the first compiler error (based on Kojiro's answer, which did not exaclty work for me):

(The need for escaped parentheses is real. I know that hurts.)

find -name '*.cpp' \( -print -a -exec g++ -c {} \; -o -quit \)

I want to build a static library of basically all C++ files located in the current directory and below.

Before running the compiler I want to have the file -print-ed, then -exec-ed, but when it fails (and leaves errors on stderr, it should -quit.

-a is like && and -o is like || in shell or C.

Without the parentheses, GNU find "optimizes" the query, by trying the most probable condition first, which is -- I guess -- -quit.

Tomasz Gandor
  • 8,235
  • 2
  • 60
  • 55
1

You could pipe the output from find to another subprocess and use while/break:

find some/path | while read f
do
    program $f
    if [ $? -ne 0 ]
    then
        break
    fi
done
Eugene Yarmash
  • 142,882
  • 41
  • 325
  • 378
  • 2
    It would be better to just do `if ! program $f; then break …`. You could also delimit across NUL instead of newlines using `-print0` and read -d'', which is safer. – kojiro Feb 14 '13 at 12:28
  • 2
    This variant apply safety suggestions from @kojiro, which are important if files contain spaces. For that you also need quotes around the `$f`. (and note it uses bash-specific `$''`). It's smaller too: `find path -print0 | while read -d $'\0' f; do command "$f" || break; done` – darque Feb 15 '13 at 02:02
0
% _find_trap() {
>   _find_pid="${1}" ; _find_ops="${2}" ; _find_trigger="${3}"
>   shift 3 && set -- "${@}" 
>   trap 'kill -s INT "-${_find_pid}" \
>     unset _find_pid _find_ops _find_trigger ; set - \
>     1>&2 printf "%s" "find killed due to trap" \
>     exit [CODE] ' TRAP
>  while { sh -c "${_find_ops} ${@}"} {
>    [ "${_find_trigger}" ] && { kill -s TRAP "-${_find_pid}" ; break ; }
>    ...
>  }
> export -f _find_trap ; find . -execdir _find_trap \"$$\" \"${cmds}\" \
>   \"${testable_trigger}\" "{}" +
mikeserv
  • 694
  • 7
  • 9