I'm currently building a script to handle some files in a directory. In the first example, I use the find command and pass a directory in as the argument. In the second I instead use the -name switch on the find command to pass the desired file-name. Can someone however explain to me the difference between the two below? As they produce exactly the same output:
find dump* -type f -mtime +5 | xargs ls -ltrh
find $dir -type f -name "dump*" -mtime +5 | xargs ls -ltrh
Please assume in the case of the top example that it's being ran in the directory containing the files. In the second however, it can be ran from wherever. My main concern is around the filepath vs -name part; so please focus your attention that way if you can.
Apologies if this has been asked before. I tried looking, but was unable to find anything on it.
Thanks.
1 Answer 1
In the first case, dump*
is interpreted by the shell, and expanded into matching filenames, and then passed to find
. In effect, find
sees:
find dumpa dumpb ... -type f ...
In the second case, no interpretation is done by the shell. find
does the filtering. Therefore, considering the recursive nature of find
, the second method can locate files which the first will miss.
The second method is more flexible, as you can use variables in forming the -name
/-path
filters, but it's tricky to get the shell to expand a wildcard in a variable. Depending on what your use case is, either would be correct, but the second can corrected to match the first in all cases (using additional find
options, such as maxdepth
, or prune
), but the reverse isn't true.
Consider:
$ tree .
.
├── dumpa
│ └── dumpc
├── dumpb
├── dumpd
└── not-dump
└── dumpe
$ find . -type f -name 'dump*'
./not-dump/dumpe
./dumpd
./dumpa/dumpc
$ find dump* -type f
dumpa/dumpc
dumpd
Also note that, if nothing matches the wildcard, the first will result in an error, but the second will succeed without any results:
$ find blahblah* -type f
find: `blahblah*': No such file or directory
$ find . -name 'blahblah*' -type f
$
I would prefer the second method because:
- It's more flexible.
- Less error-prone. Using wildcards where nothing matches can cause trouble. I avoid shell expansion of wildcards if I can, especially if I have a tool like
find
at hand.
And an unrelated point, skip the xargs
:
find ... -exec ls -lrth {} +
-
In my case, there's no sub-directories at all. From what I'm gathering, the first is more efficient because of it's nature (expanding directly into file-names), as opposed to how find approaches it. So, with the above in mind, do you suggest a specific method?Hugh– Hugh2014年12月02日 15:33:35 +00:00Commented Dec 2, 2014 at 15:33
-
Then I begin to wonder if you need
find
at all. Why notls -ltrh dump*
directly? Too many files?muru– muru2014年12月02日 15:35:01 +00:00Commented Dec 2, 2014 at 15:35 -
2Both
xargs ls -t
and-exec ls -t {} +
won't work correctly iffind
/xargs
end up running several invocations ofls
because the list is too long.Stéphane Chazelas– Stéphane Chazelas2014年12月02日 15:55:50 +00:00Commented Dec 2, 2014 at 15:55 -
@StéphaneChazelas indeed, and given that OP is running
find
instead ofls dump*
, I wonder if there are too many files.muru– muru2014年12月02日 15:58:28 +00:00Commented Dec 2, 2014 at 15:58 -
1@Hugh-Jersey I'd need to becnhmark that. Also, consider using
find
's-delete
, in either case.muru– muru2014年12月02日 16:10:38 +00:00Commented Dec 2, 2014 at 16:10