1

I have a problem with find. It doesn't find *.sh files if I am in certain directory level. It does, however, find *.sql files.

/path$ cd do_not_upload/updates/1.1.1/
/path/do_not_upload/updates/1.1.1$ find . -path *.sh
./run_pre_update/002.sh
./run_pre_update/001.sh
./run_post_update/001.sh
/path/do_not_upload/updates/1.1.1$ find . -path *.sh
./run_pre_update/002.sh
./run_pre_update/001.sh
./run_post_update/001.sh
/path/do_not_upload/updates/1.1.1$ cd ..
/path/do_not_upload/updates$ find . -path *.sh
./1.1.3/run_pre_update/002.sh
./1.1.3/run_pre_update/001.sh
./1.1.3/run_post_update/001.sh
./1.1.1/run_pre_update/002.sh
./1.1.1/run_pre_update/001.sh
./1.1.1/run_post_update/001.sh
/path/do_not_upload/updates$ cd ..
/path/do_not_upload$ find . -path *.sh
./updates/1.1.3/run_pre_update/002.sh
./updates/1.1.3/run_pre_update/001.sh
./updates/1.1.3/run_post_update/001.sh
./updates/1.1.1/run_pre_update/002.sh
./updates/1.1.1/run_pre_update/001.sh
./updates/1.1.1/run_post_update/001.sh
/path/do_not_upload$ cd ..
/path$ find . -path *.sh
/path$ find . -path *.sql
./do_not_upload/updates/1.1.3/sql_migrations/002.sql
./do_not_upload/updates/1.1.3/sql_migrations/001.sql
./do_not_upload/updates/1.1.1/sql_migrations/002.sql
./do_not_upload/updates/1.1.1/sql_migrations/001.sql

$ find --version
find (GNU findutils) 4.4.2

/path$ stat do_not_upload/
  File: ‘do_not_upload/’
  Size: 60          Blocks: 0          IO Block: 4096   directory
Device: 14h/20d Inode: 159862      Links: 3
Access: (0775/drwxrwxr-x)  Uid: ( 1000/  jorgee)   Gid: ( 1000/  jorgee)
Access: 2014-09-10 14:02:34.449376973 -0300
Modify: 2014-09-10 13:54:13.805363567 -0300
Change: 2014-09-10 13:54:13.805363567 -0300
 Birth: -
JorgeeFG
  • 735
  • 2
    Is do_not_upload a symlink? Also, don't forget to quote the *.sh so the shell doesn't expand it. – Mikel Sep 10 '14 at 19:38
  • @Mikel, no, its not a symlink. It is outputof rsync – JorgeeFG Sep 10 '14 at 19:39
  • Mind adding the output of stat do_not_upload to confirm? – Mikel Sep 10 '14 at 19:40
  • Thanks! I see your point about do_not_upload/.../sql_migrations too. – Mikel Sep 10 '14 at 19:43
  • Altho I don't think it's the problem, can you try putting quotes around *.sh and *.sql? It's a good habit anyway. – Mikel Sep 10 '14 at 19:45
  • To @Mikel's point, try find . -follow -path '*.sh'. – dg99 Sep 10 '14 at 19:50
  • @Mikel You seem to be right, adding " to the *.sh does work.... However I don't understand why it doesn't work for .sh and does work for .sql (without the ") – JorgeeFG Sep 10 '14 at 19:57
  • 1
    @Mikel maybe the answer lays in that there ARE files ending in .sh in that directory, from which I am starting the find. However, there are not .sql files. My guess now is that bash is expanding that to all the files in the directory ending with .sh – JorgeeFG Sep 10 '14 at 20:03
  • 1
    @Jorge That seems likely - iirc, the bash options nullglob and failglob can be used to change bashs behaviour when globbing fails a bit. – Wieland Sep 10 '14 at 21:02

2 Answers2

3

On Unix-like systems, *.sh is a glob expression that is expanded by the shell and the results are passed as arguments to the program being invoked. If and only if there are no matching files will the glob expression be passed as-is. You should get in the habit of quoting wildcards if you want them to be passed to the program you're running.

As an example, if you were to run find . -path *.sh from /path/do_not_upload/updates/1.1.1/run_pre_update/, the actual command being executed would be find . -path 001.sh 002.sh, which is almost certainly not what you want.

Note that this differs from MS-DOS and related systems, where glob expansion is done (or not done) by the program being invoked.

To prevent shell expansions, enclose the argument in double or even single quotes - that will pass it to the invoked program verbatim and thus let find do its own expansions:

$ find . -path '*.sh'
peterph
  • 30,838
Mark
  • 4,244
  • Note that the behavior of a glob when it does not match anything is not guaranteed. In bash it is even configurable (as @Wieland mentioned in the comments above). – dg99 Sep 10 '14 at 22:47
1

This is mostly a duplicate of this question, but the reason you get no output is a bit different.

With -path, the argument must match the entire path (including the command line argument). When foo.sh exists in the current directory, you're executing

find . -path foo.sh

Because foo.sh does not match ./foo.sh, you get no output.

The solution is the same as the linked question: quote your wildcards if you don't want the shell to expand them.

cjm
  • 27,160