find command behaviour when matching names without quotes

I was looking for differences in the find command with double quotes and without quotes.

I found something odd. I have two files:

  • xWrapper.java
  • YWrapper.java

and some in the pattern *Wrapper.java.

I ran

find . -name *Wrapper.java

which should return the first file that matches the pattern, because the command expands as

find . -name xWrapper.java yWrapper.java ..

But as a result, I got the all the files of that form. Why did it return all the files matching that pattern?

1

3 Answers

If anything you should get an error message if you are in the same catalog:

~$ mkdir test
~$ cd test
~/test$ touch {X,Y}Wrapper.java
~/test$ find . -name *Wrapper.java
find: paths must precede expression: YWrapper.java
Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]

since the asterisk will be expanded, and -name only takes a single argument.

If you come from a location where the asterisk is not expanded:

~/test$ cd ..
~$ find test -name *Wrapper.java
test/XWrapper.java
test/YWrapper.java

Since the asterisk is now not expanded (as long as it does not match anything in the current directory), find sees it "as is", and uses it as a wildcard.

You should wrap the -name argument in single quotes to avoid such context dependent behavior:

~/test$ find . -name '*Wrapper.java'
./XWrapper.java
./YWrapper.java
2

You can use the or function because -name is a single string argument.

find . \( -name "xWrapper.java" -o -name "yWrapper.java" \)

Or you can use regex to find the file with

find . -regex '.*\(x\|y\)Wrapper.java'
1
[max@localhost ~]$ touch 1file
[max@localhost ~]$ touch 2file
[max@localhost ~]$ touch 3file
[max@localhost ~]$ touch 4file
[max@localhost ~]$ touch 5file
[max@localhost ~]$ find -name "*file"
./4file
./2file
./Desktop/new file
./Desktop/DESKTOP/new file
./.bash_profile
./#file
./3file
./1file
./5file
./file
./file/file

This will match all the filename ending with file

[max@localhost ~]$ find . -name 'file*'
./file1
./.gconf/apps/file-roller
./Downloads/
./Downloads/
./Downloads/
./.gnome2/file-roller
./.local/share/Trash/files
./file
./file/file2
./file/file

This will match all the filename staring with file

[max@localhost ~]$ find -name "1file"
./1file

This will match only filename 1file

[max@localhost ~/avi]$ touch a
[max@localhost ~/avi]$ touch b
[max@localhost ~/avi]$ touch "a b"
[max@localhost ~/avi]$ ll
total 0
-rw-rw-r-- 1 max max 0 Jul 31 13:49 a
-rw-rw-r-- 1 max max 0 Jul 31 13:49 a b
-rw-rw-r-- 1 max max 0 Jul 31 13:49 b
[max@localhost ~/avi]$ find . -name a
./a
[max@localhost ~/avi]$ find . -name b
./b
[max@localhost ~/avi]$ find . -name a b
find: paths must precede expression: b
Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...]
[expression]
[max@localhost ~/avi]$ find . -name "a b"
./a b

(" or ') symbol will useful when there is a space in between filename like "a b"

1

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

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

You Might Also Like