2

I have this command:

ls -Ra | grep -cve/ -e'^\.*$'

and I would like to do exactly the same with find

I tried this find . -name "^\.*$" -o -print | wc -l but the problem is, if I create new file like this: touch "^.*$" It will not work out the same way.

Please, any idea, how to change it to make it work the same?

1
  • I think that I have found out where is the problem. in -e. But what difference it makes?
    – Mafi
    Apr 20, 2016 at 11:45

2 Answers 2

2

The problem

What are you trying to do? Let me try to explain your command so I understand it:

ls -Ra | grep -cve/ -e'^\.*$' will give you:

  • The number of files, directories, symbolic links, ...
  • Including the current directory
  • Excluding files with names only consisting of dots: touch '...' (!!!)

The solution

If you want to do the exactly the same with find, you can use:

find . -not -regex '^\.+$' | wc -l

If the more-than-two-dots files thing is a mistake, this is it:

find . | wc -l

Or (theoretically) the 'ls' way by using the following - making the a uppercase won't print current and parent directory:

ls -RA | grep -cve/ -e^\$

A little bit about timing

               except multidots    all files    number of files
  ls /home                0.75s        0.70s            ~330000
find /home                0.50s        0.50s            ~330000
  ls /                    2.50s        2.50s           ~1350000
find /                    1.90s        1.70s           ~1350000
  ls / [BSD]             10.00s        8.50s            ~250000
find / [BSD]              7.50s        7.50s            ~250000

You can see, find is pretty much always faster. But we didn't optimize it yet!

Adding the option -f to ls skips sorting and thus speeds up the process by approximately 30% (yielding 1.60s for /), making ls -RAf | grep -cve/ -e^\$ the fastest one of the commands. However, it seems to do nothing on FreeBSD...

Good to know: The extreme time difference when checking for multiple dots on BSD (FreeBSD in this case) probably originates mainly from the way GNU Grep works and the fact that it's a lot faster.
The longer times on BSD vs Linux probably are just because the BSD machine I tested this on is a lot slower, and maybe also because it's using another file system.

TL;DR

The fastest command to get the number of all filesystem nodes inside a directory with standard tools on Linux is:

ls -RAf | grep -cve/ -e^\$

A shorter command which is also the faster one on FreeBSD (and, additionally, actually answers your question) is:

find . | wc -l
0

The difference is that if you use -name you only match against the basename of the file. From man find:

-name pattern
     Base of  file  name  (the  path  with  the  leading  directories
     removed)  matches  shell  pattern  pattern.   The metacharacters
     (`*', `?', and `[]') match a `.' at the start of the  base  name
     (this is a change in findutils-4.2.2; see section STANDARDS CON‐
     FORMANCE below). <snip>

To get similar behaviour as when using ls -Ra you should be using -regex:

-regex pattern
     File  name  matches regular expression pattern.  This is a match
     on the whole path, not a search. <snip>

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.