296

I am having a hard time getting find to look for matches in the current directory as well as its subdirectories.

When I run find *test.c it only gives me the matches in the current directory. (does not look in subdirectories)

If I try find . -name *test.c I would expect the same results, but instead it gives me only matches that are in a subdirectory. When there are files that should match in the working directory, it gives me: find: paths must precede expression: mytest.c

What does this error mean, and how can I get the matches from both the current directory and its subdirectories?

Chris Finley
  • 3,901
  • 5
  • 24
  • 32
  • 7
    for the record, `find` of [msysgit](https://msysgit.github.io/) may throw this error unless you surround the pattern with quotes: `find . -name "*test.c"`. (In case you choose to prefer it over Windows' different [`find.exe`](http://technet.microsoft.com/en-us/library/cc725655%28v=ws.10%29.aspx) and use from cmd) – n611x007 Nov 14 '14 at 12:14

9 Answers9

483

Try putting it in quotes -- you're running into the shell's wildcard expansion, so what you're acually passing to find will look like:

find . -name bobtest.c cattest.c snowtest.c

...causing the syntax error. So try this instead:

find . -name '*test.c'

Note the single quotes around your file expression -- these will stop the shell (bash) expanding your wildcards.

Chris J
  • 30,688
  • 6
  • 69
  • 111
  • 15
    By way of example, you can see what's happening if you do `echo *test.c` ... the result won't be echo expanding the wildcard, but the shell itself. The simple lesson is if you're using wildcards, quote the filespec :-) – Chris J Jun 27 '11 at 17:21
  • Thanks for helping me with this VARIANT. I tried `find . -type f -printf ‘%TY-%Tm-%Td %TT %p\n’` as found on the web, and was met with "paths must precede expression". Problem was the quote marks were too "smart". I retyped the command, causing the quotes to be replaced, and it ran. – Smandoli Jan 07 '13 at 16:17
  • 2
    For some reason single quotes didn't work for me. I had to use double quotes. ¯\\_(ツ)_/¯ – Planky Mar 24 '17 at 21:41
  • single quotes for wildcard searches worked with Busybox & GNU `find` - if using a wildcard `*.$variable` you need double quotes. – Stuart Cardall Mar 26 '17 at 17:01
  • @Planky: I put : find , -name 'write.lock' in shell script file but it has this error message. But if I type in console, it works. Anyone knows why? – Scott Chu Jun 13 '17 at 03:21
  • 1
    You may aslo escape the `*` with a backslash '\' as stated by other users here. A helpful guide about the _notorious_ `find` can be found [here](http://www.oracle.com/technetwork/articles/calish-find-087766.html) – ira Jan 05 '18 at 07:38
34

What's happening is that the shell is expanding "*test.c" into a list of files. Try escaping the asterisk as:

find . -name \*test.c
Jim Garrison
  • 85,615
  • 20
  • 155
  • 190
24

From find manual:

NON-BUGS         

   Operator precedence surprises
   The command find . -name afile -o -name bfile -print will never print
   afile because this is actually equivalent to find . -name afile -o \(
   -name bfile -a -print \).  Remember that the precedence of -a is
   higher than that of -o and when there is no operator specified
   between tests, -a is assumed.

   “paths must precede expression” error message
   $ find . -name *.c -print
   find: paths must precede expression
   Usage: find [-H] [-L] [-P] [-Olevel] [-D ... [path...] [expression]

   This happens because *.c has been expanded by the shell resulting in
   find actually receiving a command line like this:
   find . -name frcode.c locate.c word_io.c -print
   That command is of course not going to work.  Instead of doing things
   this way, you should enclose the pattern in quotes or escape the
   wildcard:
   $ find . -name '*.c' -print
   $ find . -name \*.c -print
melpomene
  • 84,125
  • 8
  • 85
  • 148
Nick Constantine
  • 963
  • 9
  • 19
22

Try putting it in quotes:

find . -name '*test.c'
rkulla
  • 2,494
  • 1
  • 18
  • 16
6

I see this question is already answered. I just want to share what worked for me. I was missing a space between ( and -name. So, the correct way of chosen files with excluding some of them would be like below;

find . -name 'my-file-*' -type f -not \( -name 'my-file-1.2.0.jar' -or -name 'my-file.jar' \) 
cell-in
  • 709
  • 2
  • 11
  • 27
2

I came across this question when I was trying to find multiple filenames that I could not combine into a regular expression as described in @Chris J's answer, here is what worked for me

find . -name one.pdf -o -name two.txt -o -name anotherone.jpg

-o or -or is logical OR. See Finding Files on Gnu.org for more information.

I was running this on CygWin.

HappyTown
  • 6,036
  • 8
  • 38
  • 51
0

You can try this:

cat $(file $( find . -readable) | grep ASCII | tr ":" " " | awk '{print $1}')

with that, you can find all readable files with ascii and read them with cat

if you want to specify his weight and no-executable:

cat $(file $( find . -readable ! -executable -size 1033c) | grep ASCII | tr ":" " " | awk '{print $1}')
0

I got this error when I forgot the space between the ( and -name.

find . -not \(-name 'scripts' \)

Should have been

find . -not \( -name 'scripts' \)
Jerinaw
  • 5,260
  • 7
  • 41
  • 54
-1

In my case i was missing trailing / in path.

find /var/opt/gitlab/backups/ -name *.tar
Vikash Singh
  • 884
  • 8
  • 11