在/ usr /斌/发现:不能动态地生成它的参数 [英] /usr/bin/find: cannot build its arguments dynamically
问题描述
下面的命令作品交互预期,在终端。
The following command works as expected interactively, in a terminal.
$ find . -name '*.foo' -o -name '*.bar'
./a.foo
./b.bar
$
然而,如果我这样做,我没有得到任何结果!
However, if I do this, I get no results!
$ ftypes="-name '*.foo' -o -name '*.bar'"
$ echo $ftypes
-name '*.foo' -o -name '*.bar'
$ find . $ftypes
$
我的理解是/是 $ ftypes
将由庆典
在得到扩展找到
有机会运行。在这种情况下, ftypes
办法也应该有工作。
My understanding was/is that $ftypes
would get expanded by bash
before find
got a chance to run. In which case, the ftypes
approach should also have worked.
这是怎么回事呢?
提前非常感谢。
PS:我有一个需要动态地建立文件类型的列表(上面的 ftypes
变量)必须考虑到找到
在脚本更高版本。
PS: I have a need to dynamically build a list of file types (the ftypes
variable above) to be given to find
later in a script.
推荐答案
这两个答案至今都使用推荐的评估
,但对造成错误一个名不虚传。这里是那种怪异行为可以用此得到的例子:
Both answers so far have recommended using eval
, but that has a well-deserved reputation for causing bugs. Here's an example of the sort of bizarre behavior you can get with this:
$ touch a.foo b.bar "'wibble.foo'"
$ ftypes="-name '*.foo' -o -name '*.bar'"
$ eval find . $ftypes
./b.bar
为什么没有把它找到该文件./a.foo?这是因为那评估
命令得到了究竟是如何解析的。庆典的分析是这样的(还剩下了一些无关紧要的步骤):
Why didn't it find the file ./a.foo? It's because of exactly how that eval
command got parsed. bash's parsing goes something like this (with some irrelevant steps left out):
- 的bash查找第一个引号(没有找到 - 至今)。
- bash的替代变量。(但不回去看看在替代值报价 - 这是导致摆在首位的问题)
- bash所做的通配符匹配(在这种情况下,它会查找匹配的文件
'* foo的
和'。*栏
- 请注意,它并没有解析的报价,所以它只是将它们作为文件名的一部分来匹配 - 并发现'wibble.foo
和替代它'* foo的
)。在此之后,命令大致评估发现。 -name'wibble.fooO*的.bar'
。顺便说一句,如果发现多个匹配的东西会一直被最终得到甚至更傻。 - 庆典看到就行的命令是
评估
,并在运行整个分析过程就行的其余部分。 - 庆典再做报价匹配,这时候发现两个单引号字符串(所以它会跳过该命令的那部分最解析)。
- 的bash寻找变量替换和通配符搭配,等等,但目前还没有任何命令的不带引号的部分。
- 最后,运行bash的
找到
,传递的参数。,-name,wibble.foo,O,-name和*的.bar。 -
找到
找到一个匹配*的.bar,却敌不过wibble.foo。它甚至从来没有知道你想它寻找* .foo此时。
- bash looks for quotes first (none found -- yet).
- bash substitutes variables (but doesn't go back and look for quotes in the substituted values -- this is what lead to the problem in the first place).
- bash does wildcard matching (in this case it looks for files matching
'*.foo'
and'*.bar'
-- note that it hasn't parsed the quotes, so it just treats them as part of the filename to match -- and finds'wibble.foo'
and substitutes it for'*.foo'
). After this the command is roughlyeval find . -name "'wibble.foo'" -o "'*.bar'"
. BTW, if it had found multiple matches things would've gotten even sillier by the end. - bash sees that the command on the line is
eval
, and runs the whole parsing process over on the rest of the line. - bash does quote matching again, this time finding two single-quoted strings (so it'll skip most parsing on those parts of the command).
- bash looks for variables to substitute and wildcards to matching, etc, but there aren't any in the unquoted sections of the command.
- Finally, bash runs
find
, passing it the arguments ".", "-name", "wibble.foo", "-o", "-name", and "*.bar". find
finds one match for "*.bar", but no match for "wibble.foo". It never even knows you wanted it to look for "*.foo".
那么,你可以做这件事?那么,在这种特殊情况下增加战略双引号(评估中找到。$ ftypes
)将prevent杂散通配符替代,但一般最好避免评估
完全。当你需要构建命令,数组是一个更好的路要走(见 BashFAQ#050 更多的讨论):
So what can you do about this? Well, in this particular case adding strategic double-quotes (eval "find . $ftypes"
) would prevent the spurious wildcard substitution, but in general it's best to avoid eval
entirely. When you need to build commands, an array is a much better way to go (see BashFAQ #050 for more discussion):
$ ftypes=(-name '*.foo' -o -name '*.bar')
$ find . "${ftypes[@]}"
./a.foo
./b.bar
请注意,您也可以通过建立位选项位:
Note that you can also build the options bit by bit:
$ ftypes=(-name '*.foo')
$ ftypes+=(-o -name '*.bar')
$ ftypes+=(-o -name '*.baz')
这篇关于在/ usr /斌/发现:不能动态地生成它的参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!