4

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.
    – user313992
    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.
    – user313992
    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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .