3

I can't for the life of me figure out how find with the test -name works.

I run find / -name *in and returns a bunch of results:

/sbin
/sbin/sulogin
/dev/stdin

to name a few.

It's as if it performed filename expansion, but that happens before the shell runs the command, so that can't be it. Also because I don't have any files in the current directory that match *in. Plus, single quoting *in yields the same results, which further supports that this can't be filename expansion.

The documentation leads me to believe that find with -name uses regular expressions, but the regex pattern *in doesn't match the results I showed above.

Can someone enlighten me?

4
  • 1
    "It's as if it performed filename expansion, but that happens before the shell runs the command, so that can't be it." But that's exactly what it is! Only that instead of matching the *in pattern against the files from the cwd, it matches it against the the files from the directories it's walking through.
    – mosvy
    Jun 12, 2019 at 0:14
  • "The documentation kind of suggests that find with -name uses regular expressions" the documentation does not suggest such thing.
    – mosvy
    Jun 12, 2019 at 0:19
  • @mosvy I edited my question.
    – Find
    Jun 12, 2019 at 0:21
  • If you need regular expressions, you can use -regex pattern which is used to match the whole path (including slashes), while -name pattern operates on the filename and uses shell patterns.
    – Freddy
    Jun 12, 2019 at 0:25

1 Answer 1

6

The parameter passed to -name is a filesystem glob pattern, the same as the you'd enter for other commands, such as ls -l *in.

For each file it finds it compares the basename of the file to the pattern you passed. So when it finds /bin/foobar it compares foobar to *in, doesn't match, skips; but with /bin/login it compares login to *in and this does match, and so prints.

Now you need to be careful because *in might be matched on the command line depending on files in the current directory.

So, for example:

$ find /bin -name *in
/bin
/bin/login

$ touch foobarin

$ find /bin -name *in
$ 

Notice the same find command returned two different results.

We can see why if we set the shell to debug mode:

$ rm foobarin 

$ set -x

$ find /bin -name *in
+ find /bin -name '*in'
/bin
/bin/login

$ touch foobarin     
+ touch foobarin

$ find /bin -name *in
+ find /bin -name foobarin

$ 

The lines starting with a + are what the shell interpreted the command entered. We can see that the second find command expanded the *in to match the existing filename.

Because of this it's recommended to quote names

$ find /bin -name '*in'
+ find /bin -name '*in'
/bin
/bin/login
4
  • Thank you, that's helpful. When you say that we should quote names. Should it be, more precisely, single quote them?
    – Find
    Jun 12, 2019 at 0:14
  • The quote will depend on how you want the command line to interpret your input, same as everywhere else. So if you're looking for a file called $foo then you may use '$foo' but if you want to expand the variable then you may use "$foo". This isn't specific to the find command, but is how the command line works. Jun 12, 2019 at 0:17
  • But won't the variable be expanded just like * was when you used single quotes? EDIT: I understand this expansion occurs after the command is ran, contrarily to "regular expansion".
    – Find
    Jun 12, 2019 at 0:19
  • No; command line globs don't follow variable expansion. eg if we set $ foo='*in' then the command $ find /bin -name "$foo" will give the debug output + find /bin -name '*in' which is exactly what we want. Jun 12, 2019 at 0:21

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.