7
find ~/ -name *test.txt
find ~/ -name '*test.txt'

I need to construct an example where the first form fails but the second still works.

4 Answers 4

21

The quotes protect the contents from shell wildcard expansion. Run that command (or even simpler just echo *test.txt in a directory with a footest.txt file and then one without any files that end in test.txt and you will see the difference.

$ ls
a  b  c  d  e
$ echo *test.txt
*test.txt
$ touch footest.txt
$ echo *test.txt
footest.txt

The same thing will happen with find.

$ set -x
$ find . -name *test.txt
+ find . -name footest.txt
./footest.txt
$ find . -name '*test.txt'
+ find . -name '*test.txt'
./footest.txt
$ touch bartest.txt
+ touch bartest.txt
$ find . -name *test.txt
+ find . -name bartest.txt footest.txt
find: paths must precede expression
Usage: find [-H] [-L] [-P] [path...] [expression]
$ find . -name '*test.txt'
+ find . -name '*test.txt'
./bartest.txt
./footest.txt
0
1

tl;dr version

You are passing a string literal to the command/program, just like double-quotes but differ that single-quotes prevent variable and wildcard expansion while double-quotes expand them in to the string literal.

Example:

$ export MY_VAR=my_string
$ echo "$MY_VAR"
my_string
$ echo '$MY_VAR'
$MY_VAR

The same applies to wildcards

EDIT:

An example like the one you asking is IMO impossible, because any literal that the second command matches will be inevitable matched by the wildcard in the first command.

2
  • Thank you! I got the point between "" and ''. How about the question I mentioned above?
    – Yunong
    Nov 26, 2014 at 23:40
  • There's no wildcard expansion inside double-quotes. Your last sentence doesn't make sense either. Nov 27, 2014 at 14:40
0

To complement the other answers, zsh, fish and (t)csh are more helpful here in that they can help you show your mistake before it becomes a problem:

If there's no *test.txt file in the current directory:

zsh$ find . -name *test.txt
zsh: no matches found: *test.txt

fish> find . -name *test.txt
fish: No matches for wildcard '*test.txt'.
find . -name *test.txt
             ^

tcsh> find . -name *test.txt
find: No match.

fish and zsh are correct in making it clear that it's the shell (not find) that is complaining here, while tcsh's error is misleading. (tcsh only reports No match however if all the globs on the command line fail to match. If some match and some don't, those that don't will expand to themselves like in Bourne-like shells).

With bash, you can obtain the same behaviour with:

$ shopt -s failglob
$ find . -name *test.txt
bash: no match: *test.txt
1
  • failglob is present at least as far back as bash 3.2.25 (CentOS 5) so I'm not sure that counts as "recent" at this point. Nov 28, 2014 at 13:04
-3

In the first case, the argument *test.txt is considered an operator of the find command itself whereas with quotes, the argument *test.txt will be considered a parameter to a switch of find.

If you have more than one text files with the .txt extension in your current directory, the following will fail as find will not see a *.txt argument:

find . -name *.txt

Whereas this will succeed:

find . -name '*.txt'
2
  • 13
    That's wrong, the correct answer is the one from @etan reisner, it's a case of shell expansion before it even reaches to find. Nov 27, 2014 at 0:57
  • Ok, I realize that.
    – Ketan
    Nov 27, 2014 at 19:08

You must log in to answer this question.

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