Bash:命令替换中的引用

Bash:命令替换中的引用

简而言之,我想在命令中使用命令列出的目录find

find $(produces_dir_names --options...) -find-options...

问题在于目录名称中存在空格。我认为在生成命令的输出中引用它们(我可以更改)就足够了:

"a" "a b" "a b c"

但 bash 抱怨道:

find: ‘"a"’: No such file or directory
find: ‘"a’: No such file or directory
find: ‘b"’: No such file or directory
find: ‘"a’: No such file or directory
find: ‘b’: No such file or directory
find: ‘c"’: No such file or directory

如您所见, seebash会在空格上分割命令的输出,即使使用引号也是如此。我尝试摆弄IFS并将其设置为\n,但我对它的理解似乎太有限,无法使其正常工作。

我发现的唯一解决方法是在这个 Stack Overflow 问题中: bash命令替换删除引号,即eval在它前面放一个,但这看起来有点难看。

我的问题:

有没有一种简单的方法以及在没有 的情况下编写此替换会是什么样子eval

报价还有必要吗?

示例(产生相同的输出):

find $(echo '"a" "a b" "a b c"')

答案1

也许分两行

IFS=$'\n' DIRS=( $(produces_dir_names --options...) ) 
find "${DIRS[@]}" -find-options...

例子:

$ mkdir -p "/tmp/test/a b/foo" "/tmp/test/x y/bar"

$ IFS=$'\n' DIRS=( $(printf "/tmp/test/a b\n/tmp/test/x y\n") )
$ find "${DIRS[@]}" -mindepth 1
/tmp/test/a b/foo
/tmp/test/x y/bar

但总的来说,这不是一个好的风格。例如,如果您的 DIRS 包含换行符,您就会遇到麻烦。更好地修复您的“ Produces_dir_names”以打印空字节终止的字符串。关于我的例子,这将是这样的:

$ printf "/tmp/test/a b\0/tmp/test/x y\0" | xargs -0 -I '{}' find '{}' -mindepth 1
/tmp/test/a b/foo
/tmp/test/x y/bar

如果您无法修复“products_dir_names”,则关于我的最后一条评论,最通用的解决方案将如下所示:

produces_dir_names --options... | tr '\n' '\0' | xargs -0  -I '{}' find '{}' -find-options...

除非您修复“ Produces_dir_names”以避免“换行符”,否则“换行符”仍然存在问题tr

答案2

鲁迪迈尔的回答很好——具体来说,关于修改produces_dir_names 以打印空终止字符串的部分——但从他的回答中可能并不明显看出它find为每个目录执行一次。如果这足够好,那就好了。但是,当然,可以使用find 多个起点进行调用;例如,

寻找  目录1目录2目录3  -查找选项...

从问题看来这就是你想要的。这可以按如下方式完成:

printf "a\0a b\0a b c" | printf "a\0a b\0a b c" | xargs -0 sh -c '查找“$@”-查找选项...' 什

这会导致xargs调用sh -c一次,并将所有目录名称附加到命令中。然后,shell 将展开"$@"这些目录名称的列表。

PS 如果produces_dir_names列出太多目录名称而无法放在一个命令行上,则将xargs被迫生成一些命令。用于xargs --verbose查看xargs正在生成哪些命令。

答案3

只是为了揭开您收到的错误消息的神秘面纱:

find: ‘"a"’: No such file or directory
find: ‘"a’: No such file or directory
find: ‘b"’: No such file or directory
find: ‘"a’: No such file or directory
find: ‘b’: No such file or directory
find: ‘c"’: No such file or directory

答案是Bash 引号删除不会删除以下引号结果来自命令替换。

LESS='+/^ *Quote Removal' man bash

Quote Removal
    After the preceding expansions, all unquoted occurrences of the charac-
    ters  \,  ', and " that did not result from one of the above expansions
    are removed.

引用的“前述扩展”包括:

EXPANSION
   Brace Expansion
   Tilde Expansion
   Parameter Expansion
   Command Substitution
   Arithmetic Expansion
   Process Substitution
   Word Splitting
   Pathname Expansion
   Quote Removal

相关内容