I want to use find
to find files in a set of folders restricted by wildcards, but where there are spaces in the path name.
From the command line, this is easy. The following examples all work.
find te*/my\ files/more -print
find te*/'my files'/more -print
find te*/my' 'files/more -print
These will find files in, for example, terminal/my files/more
and tepid/my files/more
.
However, I need this to be part of a script; what I need is something like this:
SEARCH='te*/my\ files/more'
find ${SEARCH} -print
Unfortunately, whatever I do, I don't seem to be able to mix wildcards and spaces in a find
command within a script. The above example returns the following errors (note the unexpected doubling of the backslash):
find: ‘te*/my\\’: No such file or directory
find: ‘files/more’: No such file or directory
Trying to use quotes also fails.
SEARCH="te*/'my files'/more"
find ${SEARCH} -print
This returns the following errors, having ignored the meaning of the quotes:
find: ‘te*/'my’: No such file or directory
find: ‘files'/more’: No such file or directory
Here's one more example.
SEARCH='te*/my files/more'
find ${SEARCH} -print
As expected:
find: ‘te*/my’: No such file or directory
find: ‘files/more’: No such file or directory
Every variation that I've tried returns an error.
I have a workaround, which is potentially dangerous because it returns too many folders. I convert all spaces to a question mark (single-character wildcard) like this:
SEARCH='te*/my files/more'
SEARCH=${SEARCH// /?} # Convert every space to a question mark.
find ${SEARCH} -print
This is the equivalent of:
find te*/my?files/more -print
This returns not only the correct folders but also terse/myxfiles/more
, which it's not supposed to.
How can I achieve what I'm trying to do? Google has not helped me 🙁
Best Answer
The exact same command should work fine in a script:
If you need to have it as a variable, it gets a bit more complex:
WARNING:
Using
eval
like that is not safe and can result in executing arbitrary and possibly harmful code if your file names can contain certain characters. See bash FAQ 48 for details.It's better to pass the path as an argument:
Another approach is to avoid
find
altogether and use bash's extended globbing features and globs:The
globstar
bash option lets you use**
to match recursively:To make it act 100% like find and include dotfiles (hidden files), use
You can even
echo
them directly without the loop: