Bash逃逸问题$@
我编写了一个脚本来简化长启动命令的运行:Bash逃逸问题$@,bash,escaping,quotes,Bash,Escaping,Quotes,我编写了一个脚本来简化长启动命令的运行: # in ~/.bash_profile function runProgram() { sbt "run-main com.longpackagename.mainclass $@ arg3"; }; export -f runProgram; 但是,当我尝试传递多个参数时,它失败了: $ runProgram arg1 arg2 ... [info] Running com.longpackagename.mainclass arg1 sbt "
# in ~/.bash_profile
function runProgram() { sbt "run-main com.longpackagename.mainclass $@ arg3"; };
export -f runProgram;
但是,当我尝试传递多个参数时,它失败了:
$ runProgram arg1 arg2
...
[info] Running com.longpackagename.mainclass arg1
sbt "run-main com.longpackagename.mainclass ""arg1" "arg2"" arg3"
arg2和arg3发生了什么?他们是被bash还是sbt吃掉的
如果我按如下方式运行脚本,它将按预期工作:
$ runProgram "arg1 arg2"
--
另外:这类问题对我来说一直都在发生。我也希望能提供一份关于如何在bash中正确逃脱的参考资料。我尝试的&resources没有解决这种情况。有关
bash
的最佳参考,包括如何引用,是bash手册本身,它几乎肯定安装在您的机器上,您可以通过键入man bash
在没有互联网连接的情况下阅读它。这本书很值得一读,但没有真正的替代品
尽管如此,我将试图解释这一特定问题。有两件重要的事情需要知道:第一,bash如何(以及何时)将命令行拆分为单独的“字”(或命令行参数);第二,什么是$@
和$*
意思。这些并非完全无关
分词部分由特殊参数IFS
控制,但我只提到了这一点;我想它没有被改变。有关更多详细信息,请参见manbash
下面,我将使用双引号(“…”
)引用字符串称为弱引用,使用撇号(“…”
)引用字符串称为强引用。反斜杠(\
)也是强引号的一种形式
发生分词:
“
,”
,\
是三种方式)manbash
)
如果参数的名称前面有一个$
,除非$name
被强烈引用(即,'$name'
或,例如,\$name
),否则将用它们的值替换参数(步骤1)。还有更多形式的参数替换。有关更多详细信息,请参见manbash
现在,$@
和$*
都表示“当前命令/函数的所有位置参数”,如果使用它们时不带引号,则它们的作用完全相同。它们将替换为所有位置参数,每个参数之间只有一个空格。由于这是一种类型的参数替换(如上所述),因此在替换之后会发生分词,除非替换在引号中,如上面的列表所示
如果替换在引号中,则根据上述规则,插入参数之间的空白不受分词的影响。这正是$*
的工作原理$*
替换为空格分隔的命令行参数,结果是单词拆分<代码>“$*”替换为以空格分隔的命令行参数作为单个单词
“$@”
是一个例外。事实上,这就是$@
存在的原因。如果$@
位于弱引号(“$@”
)内,则删除引号,并单独引用每个位置参数。然后,这些引用的位置参数被隔开并替换为$@
。由于$@
本身不再被引用,因此插入的空格确实会导致分词。最终的结果是,各个参数被保留为单个单词
如果这还不完全清楚,这里有一个例子printf
的优点是重复提供的格式,直到参数用完为止,这样可以很容易地看到发生了什么
showargs() {
echo -n '$*: '; printf "<%s> " $*; echo
echo -n '"$*": '; printf "<%s> " "$*"; echo
echo -n '"$@": '; printf "<%s> " "$@"; echo
}
showargs one two three
showargs "one two" three
为函数提供两个位置参数,以便$1
为arg1
,$2
为arg2
首先,bash删除$@
周围的引号。然而,它不能完全删除它们,因为那里也有引用的文本。因此,它必须关闭引用的文本,然后重新打开引用,从而产生:
sbt "run-main com.longpackagename.mainclass "$@" arg3"
现在,它可以在引用的分隔参数中替换:
$ runProgram arg1 arg2
...
[info] Running com.longpackagename.mainclass arg1
sbt "run-main com.longpackagename.mainclass ""arg1" "arg2"" arg3"
现在是单词拆分:
sbt
"run-main com.longpackagename.mainclass ""arg1"
"arg2"" arg3"
并删除引号:
sbt
run-main com.longpackagename.mainclass arg1
arg2 arg3
sbt
只需要一个位置参数。你给了它两个,它忽略了第二个
现在,假设使用单个参数调用函数,“arg1 arg2”
。在这种情况下,替换$@
会导致:
sbt "run-main com.longpackagename.mainclass ""arg1 arg2"" arg3"
分词会产生
sbt
"run-main com.longpackagename.mainclass ""arg1 arg2"" arg3"
不加引号:
sbt
run-main com.longpackagename.mainclass arg1 arg2 arg3"
对于
sbt
,只有一个位置参数bash
的最佳参考,包括如何引用,是bash手册本身,它几乎肯定安装在您的机器上,您可以通过键入man bash
在没有互联网连接的情况下阅读它。这本书很值得一读,但没有真正的替代品
尽管如此,我将试图解释这一特定问题。有两件重要的事情需要知道:第一,bash如何(以及何时)将命令行拆分为单独的“字”(或命令行参数);第二,什么是$@
和$*
意思。这些并非完全无关
分词部分由特殊参数IFS
控制,但我只提到了这一点;我想它没有被改变。有关更多详细信息,请参见manbash
下面,我将使用双引号(“…”
)引用字符串称为弱引号,并使用撇号(“…”)引用字符串