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: -

marked as duplicate by Gilles 'SO- stop being evil', Networker, jasonwryan, peterph, Anthon Sep 11 '14 at 10:20

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • 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
  • 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
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'
  • 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.

Not the answer you're looking for? Browse other questions tagged or ask your own question.