How to stop the find command after first match?
With GNU or FreeBSD find
, you can use the -quit
predicate:
find . ... -print -quit
The NetBSD find
equivalent:
find . ... -print -exit
If all you do is printing the name, and assuming the filenames don't contain newline characters, you could do:
find . ... -print | head -n 1
That will not stop find
after the first match, but possibly, depending on timing and buffering upon the second match or (much) later. Basically, find
will be terminated with a SIGPIPE when it tries to output something while head
is already gone because it has already read and displayed the first line of input.
Note that not all shells will wait for that find
command after head
has returned. The Bourne shell and AT&T implementations of ksh
(when non-interactive) and yash
(only if that pipeline is the last command in a script) would not, leaving it running in background. If you'd rather see that behaviour in any shell, you could always change the above to:
(find . ... -print &) | head -n 1
If you're doing more than printing the paths of the found files, you could try this approach:
find . ... -exec sh -c 'printf "%s\n" "$1"; kill "$PPID"' sh {} \;
(replace printf
with whatever you would be doing with that file).
That has the side effect of find
returning an exit status reflecting the fact that it was killed though.
Actually, using the SIGPIPE signal instead of SIGTERM (kill -s PIPE
instead of kill
) will cause some shells to be more silent about that death (but would still return a non-zero exit status).
find . -name something -print -quit
Terminates find after the first match after printing it.
Terminate find after a specific amount of matches and print results:
find . -name something -print | head -n 5
Surprisingly enough - head now terminates string after 5 matches, though I do not know how or why.
It is very easy to test. Just let find search a on root which would result thousands, maybe even more matches while taking at least a minute or more. But when piped into "head" "find" will terminate after the specified amount of lines defined in head (default head shows 10, use "head -n" to specify lines).
Note that this will terminate after "head -n" reaches the specified newline character count and therefore any match that contains multiple newline characters will count accordingly.
For entertainment purposes, here's a lazy find generator in Bash. This example generates a ring over the files in the current directory. Read however many you want then kill %+
(maybe just 1)
#!/usr/bin/env bash
unset -v files n
trap 'kill "$x_PID"' EXIT
coproc x while :; do
find . -type f -maxdepth 1 -exec sh -c "$(</dev/fd/3)" _ {} +
done 4<&0 <<\EOF 3<&0 <&4-
for x; do
read -r _
printf '%s\0' "$x"
done
EOF
while
echo >&${x[1]}
IFS= read -rd '' -u "$x" 'files[n++]'
do
printf '%q ' "${files[@]}"
echo
sleep .2
done