In a bash shell, consider this:
$ x="-name 'foo bar'"
$ find $x
find: paths must precede expression: `bar''
$ find -name 'foo bar'
./foo bar
What can I put in $x
to make find $x
behave like find -name 'foo bar'
?
In a bash shell, consider this:
$ x="-name 'foo bar'"
$ find $x
find: paths must precede expression: `bar''
$ find -name 'foo bar'
./foo bar
What can I put in $x
to make find $x
behave like find -name 'foo bar'
?
Do not put things that are separate (-name
and foo bar
) into a single string.
Instead, use an array:
args=( -name 'foo bar' )
find . "${args[@]}"
The quotes around the expansion of the array variable ensures that each element is individually quoted. This ensures that foo bar
is a single argument.
You may also use the positional parameters:
set -- -name 'foo bar'
find . "$@"
Again, the quoting of "$@"
are essential.
When you put -name 'foo bar'
in your variable and use it unquoted with find
, the shell will split the value on spaces, tabs and newlines. This means that tho find
utility gets the arguments -name
, 'foo
, and bar'
. Since the bar'
argument is unknown to find
, it complains.
If you had globbing patterns in your string, as in -name '*.txt'
, then the shell would split that into -name
and '*.txt'
, and would then use '*.txt'
as a globbing pattern to expand names in the current directory.
Note: Linux supports that find syntax, but it's not universal. It does not work on most BSD derivatives, for example, yielding the following:
bash-3.2$ find -name 'foo bar'
find: illegal option -- n
usage: find [-H | -L | -P] [-EXdsx] [-f path] path ... [expression]
find [-H | -L | -P] [-EXdsx] -f path [path ...] [expression]
Your problem isn't location, it's quoting and quote interpretation. Could you replace your code with
x='foo bar'
find -name "$x"
Alternatively, you could potentially try using eval:
x="-name 'foo bar'"
eval "find $x"
Which at least on my system resulted in:
bash-5.1$ x="-name 'foo bar'"
bash-5.1$ eval "find $x"
./foo bar
Which I believe is the desired result.