Efficient Finds
Recently, I’ve seen a lot of suggestions along the lines of:
find . -name foo -exec ls -l {} ;
This is incredibly inefficient, because for each and every matching file, ls will be executed. Fortunately, we can do better by using xargs. xargs takes a list of lines from stdin and uses them to build up a command line. It takes special care to not exceed the maximum command line length by splitting the input up into multiple commands if it is needed. So, with that knowledge, we can replace our original command with:
find . -name foo | xargs ls -l
There is one slight problem with this command; it isn’t space-safe. xargs splits arguments on whitespace, so “file name” will be incorrectly passed to the command as “file” “name”. Fortunately, xargs has an option to delimit parameters by the null character, and as our luck would have it, find has a suitable option to produce output in this format. This means our command is now:
find . -name foo -print0 | xargs -0 ls -l
mlocate can do something similar:
locate foo -0 | xargs -0 ls -l
GNU find has one more trick up its sleeve. It has a modified version of -exec that will do the same thing as xargs, so we could have written our original command as:
find . -name foo -exec ls -l {} +
Every process is sacred; every process is great. If a process is wasted, God gets quite irate. Please make sure you try to use one of the latter forms and not the first form, and make a happy deity. :)
Filed under linux
10 comments
Comments are closed. These are preserved from the original site.
I assume that you are using "ls" as an example command since find has an "-ls" option which will not need any additional processes.
I'm a newly converted fan of GNU xargs' -n 1 -P 10 (or whatever) for intensive jobs like compiling or encoding.
ls -l **/name
with zsh and bash4.
zsh also has zargs, which is used like this:
zargs -- **/name -- ls -l
ls -l **/name
with zsh and bash4.
zsh also has zargs, which is used like this:
zargs -- **/name -- ls -l
Just for clarification "-exec ... +" is not a GNUism. It is part of the Susv3/Posix standard and e.g. the find implementations on *BSD supported this before GNU findutils.
Just for clarification "-exec ... +" is not a GNUism. It is part of the Susv3/Posix standard and e.g. the find implementations on *BSD supported this before GNU findutils.
Just for clarification "-exec ... +" is not a GNUism. It is part of the Susv3/Posix standard and e.g. the find implementations on *BSD supported this before GNU findutils.
Why not simply 'find . -name foo -ls' ?
As a side note and interestingly, many people uselessly write the dot: "find . arguments".
By default find runs on the current directory so there is no need to specify it: "find arguments" is shorter.
I was telling it to a friend lately, just as he showed me that I could write "ln myfile" more concisely than "ln -s myfile ." Same stuff.
(oops in the former comment: I meant "ln -s" obviously in both cases!)