Of these two ways of searching a file recursively in all the subdirectories, which is faster / better ?
find . -regex ".*/.*abc.*"
or
find . | grep ".*abc.*"
UNIX file name can generally consist of octets (8-bit bytes), except for 0x00 (NULL) and 0x2F (/). Every other octet is valid. This includes such nice things as 0x0A (newline).
Your find
example will handle file names with weird characters such as newline correctly.
Your find | grep
example will give odd and incorrect results when faced with such a thing (it'll see one file called "line 1\nline 2" as two files).
You can use find -print0 | grep -z
(if you're using GNU versions, e.g., on Linux); that'll preserve correctness. It'll use a little more memory. Note that you can tell find to use extended regular expressions (for example) using the -regextype
option.
If you want to do some really complicated matching, you may like the find2perl
script, which will convert a find
command line in to a short perl program you can then edit to add in the complexity.
find . -regex ".*/.*abc.*"
is faster because find . | grep ".*abc.*"
has to have find
generate all the data and pass it down to grep
. The difference is likely to be small though. find . -regex ".*/.*abc.*"
is also more reliable, because it works even in the rare case where you have file names with spaces.
Note that both commands look for files whose full path contains abc
. This includes not only files whose name contains abc
but also files contained in a directory whose name contains abc
, recursively. To find only files whose name contains abc
, use
find -name '*abc*'
In ksh, bash or zsh, you can run echo **/*abc*
instead: **/
looks inside all subdirectories recursively. In ksh, you'll need to run set -o globstar
first (put this in your ~/.kshrc
). In bash, you'll need to run shopt -s globstar
first (put this in your ~/.bashrc
).
find
generate all the data"? As far as I know the data is automatically flushed regularly and passed to the pipe. That's how pipe usually works. Another example: try yes | cat
. If cat waited for all the data from yes
which is an infinite stream then it would never finally start writing data to the output.
Commented
Jan 26, 2014 at 15:16
find
generates all the data and passes it through the pipe. It does this in parallel with grep
.
Commented
Jan 26, 2014 at 15:59
If you use pattern matching with find
, you can add other predicates or behaviours:
# look only for matching directories
find . -regex ".*/.*abc.*" -type d
# run a command on each match
find . -regex ".*/.*abc.*" -exec echo 'I found a file named {}' ';'
find
might be faster for just searching, too, because you don't need to spawn a grep
process or perform any piping; but I doubt you would be able to notice.
find . -type f -iname "*abc*"
would work...