2

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.

3

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:

  1. It's more flexible.
  2. 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 Dec 2 '14 at 15:33
  • Then I begin to wonder if you need find at all. Why not ls -ltrh dump* directly? Too many files? – muru Dec 2 '14 at 15:35
  • 2
    Both xargs ls -t and -exec ls -t {} + won't work correctly if find/xargs end up running several invocations of ls because the list is too long. – Stéphane Chazelas Dec 2 '14 at 15:55
  • @StéphaneChazelas indeed, and given that OP is running find instead of ls dump*, I wonder if there are too many files. – muru Dec 2 '14 at 15:58
  • 1
    @Hugh-Jersey I'd need to becnhmark that. Also, consider using find's -delete, in either case. – muru Dec 2 '14 at 16:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.