Bash在引用参数列表时插入额外的,不正确的单引号

时间:2014-07-14 19:20:09

标签: bash

我正在尝试使用某些参数创建一个运行Maven的程序。

它基本上是这样做的:

ARGUMENTS=\""${@:2}"\"
mvn exec:java -Dexec.mainClass=$1 -Dexec.args=$ARGUMENTS

因此运行./myScript.sh a b c会导致运行:

mvn exec:java -Dexec.mainClass=a -Dexec.args="b c"

但Maven正在抛出一个未知生命周期的错误。在那里投掷set -x告诉我该命令实际上变成了:

mvn exec:java -Dexec.mainClass=a '-Dexec.args="b' 'c"'

回应$ARGUMENTS会给出预期的"b c"。是什么导致添加这些额外的报价,我该如何解决这个问题以获得我的预期结果?

2 个答案:

答案 0 :(得分:5)

arguments="${*:2}"
mvn exec:java -Dexec.mainClass="$1" -Dexec.args="$arguments"

有关完整说明,请参阅BashFAQ #50。那说:

"$@"维护argv数组元素之间的分割 - 也就是说--foo="$@",当set -- hello world解析为"--foo=hello" "world"时。

"$*"将argv数组元素与它们之间的第一个IFS字符组合在一起,默认情况下为空格。

没有双引号的

$*执行相同的但是无法阻止字符串拆分或全局扩展,因此组合所有参数,但随后允许shell再次将它们拆分(并扩展它们包含的globs) - 一种很少需要的行为。

arguments="\"${*:2}\""创建一个字符串 - "hello world"。运行-Dexec.args=$arguments时,会经历几个处理阶段(不包括与当前数据集无关的阶段,例如glob扩展):

  • 发生语法分析。在此阶段,仅在此阶段,当shell确定引用哪些字符以及如何引用时。由于-Dexec.args=$arguments中不存在字面引号,因此唯一的扩展记录为不带引号。
  • 发生扩张。此时,展开的字符串看起来像-Dexec.args="hello world"
  • 发生字符串拆分。由于解析阶段已经处理,记录和删除了语法引号,因此剩余的任何引号都是数据,并被处理为单个单词。因此,-Dexec.args="hello是一个单词,而world"是一个单词。

将此与正确用法进行比较,-Dexec.args="$arguments"(或其有效等效值,"-Dexec.args=$arguments")。此时:

  • 发生语法分析。这将删除$arguments周围的双引号,并将扩展标记为双引号。
  • 发生扩张。如果您在arguments数组中仍然包含字面引号,则它们会被替换为数据,使-Dexec.args="hello world"将文字数据传递给Maven,包括引号字符本身
  • 字符串拆分发生在扩展字符串上。在这种情况下,因为语法分析将扩展标记为双引号,所以它没有效果。

如果您不希望将文字引号字符传递给Maven(并且您不应该这样做),只需省略它们,并仅使用语法引号,如本答案顶部的示例所示。

答案 1 :(得分:3)

似乎是引用问题。尝试使用BASH数组:

arr=( "$@" )
mvn exec:java -Dexec.mainClass="$1" -Dexec.args="${arr[*]:1}"