在/ usr /斌/发现:不能动态地生成它的参数 [英] /usr/bin/find: cannot build its arguments dynamically

查看:111
本文介绍了在/ usr /斌/发现:不能动态地生成它的参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面的命令作品交互预期,在终端。

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


  1. 的bash查找第一个引号(没有找到 - 至今)。

  2. bash的替代变量。(但不回去看看在替代值报价 - 这是导致摆在首位的问题)

  3. bash所做的通配符匹配(在这种情况下,它会查找匹配的文件'* foo的'。*栏 - 请注意,它并没有解析的报价,所以它只是将它们作为文件名的一部分来匹配 - 并发现'wibble.foo 和替代它'* foo的)。在此之后,命令大致评估发现。 -name'wibble.fooO*的.bar'。顺便说一句,如果发现多个匹配的东西会一直被最终得到甚至更傻。

  4. 庆典看到就行的命令是评估,并在运行整个分析过程就行的其余部分。

  5. 庆典再做报价匹配,这时候发现两个单引号字符串(所以它会跳过该命令的那部分最解析)。

  6. 的bash寻找变量替换和通配符搭配,等等,但目前还没有任何命令的不带引号的部分。

  7. 最后,运行bash的找到,传递的参数。,-name,wibble.foo,O,-name和*的.bar​​。

  8. 找到找到一个匹配*的.bar​​,却敌不过wibble.foo。它甚至从来没有知道你想它寻找* .foo此时。

  1. bash looks for quotes first (none found -- yet).
  2. 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).
  3. 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 roughly eval find . -name "'wibble.foo'" -o "'*.bar'". BTW, if it had found multiple matches things would've gotten even sillier by the end.
  4. bash sees that the command on the line is eval, and runs the whole parsing process over on the rest of the line.
  5. bash does quote matching again, this time finding two single-quoted strings (so it'll skip most parsing on those parts of the command).
  6. bash looks for variables to substitute and wildcards to matching, etc, but there aren't any in the unquoted sections of the command.
  7. Finally, bash runs find, passing it the arguments ".", "-name", "wibble.foo", "-o", "-name", and "*.bar".
  8. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆