当直接调用b2命令而不是从间接bash脚本变量

时间:2018-11-08 19:04:15

标签: bash boost compilation

我的bash脚本有一个奇怪的问题。我将boost编译为其中的一部分。脚本中的调用如下所示:

./b2 --reconfigure ${PARALLEL} link=static cxxflags=-fPIC install boost.locale.iconv=off boost.locale.posix=off -sICU_PATH="${ICU_PREFIX}" -sICU_LINK="${BOOST_ICU_LIBS}" >> "${BOOST_LOG}" 2>&1

该命令运行良好。日志文件显示它找到ICU没有问题。但是,如果我将其更改为从变量运行,它将不再找到ICU(但仍会编译其他所有内容):

bcmd="./b2 --reconfigure ${PARALLEL} link=static cxxflags=-fPIC install boost.locale.iconv=off boost.locale.posix=off -sICU_PATH=\"${ICU_PREFIX}\" -sICU_LINK=\"${BOOST_ICU_LIBS}\""
$bcmd >> "${BOOST_LOG}" 2>&1

有什么区别?我希望能够使用第二种方法,以便可以在运行命令之前将命令传递给另一个函数。

3 个答案:

答案 0 :(得分:3)

不要使用变量来存储涉及嵌套引号的复杂命令。问题是,当您仅使用$cmd调用变量时,引号被错误地剥离。将命令(或命令的一部分)放入变量,然后将它们完整地取出,这很复杂。

除去行号是shell进行的单词扩展之一的一部分。摘自POSIX shell规范

  

2.6.7删除报价

     

原始单词中出现的引号字符(反斜杠,单引号和双引号)应被删除,除非它们本身已被引号。

您的示例可以通过一个简单示例简单地复制。假设您有几个命令标记(不是实际的)

cmdFlags='--archive --exclude="foo bar.txt"'

如果您仔细阅读以上内容,它包含2个参数,一个为--archive,另一个为--exclude="foo bar.txt",请注意在传递时需要保留双引号。

请注意,在下面的cmdFlags调用中,当我不引用printf()时,如何将引号错误地分开

printf "'%s' " $cmdFlags; printf '\n'
'--archive' '--exclude="foo' 'bar.txt"'

并将结果与​​下面正确引用的结果进行比较。

printf "'%s' " "$cmdFlags"; printf '\n'
'--archive --exclude="foo bar.txt"'

因此,除了正确引用变量的建议外,通常的建议是使用数组存储标志并传递引用的数组扩展

cmdArray=()
cmdArray=(./b2 --reconfigure ${PARALLEL} link=static cxxflags=-fPIC install boost.locale.iconv=off boost.locale.posix=off -sICU_PATH="${ICU_PREFIX}" -sICU_LINK="${BOOST_ICU_LIBS}")

并将数组传递为

"${cmdArrray[@]}" >> "${BOOST_LOG}" 2>&1

答案 1 :(得分:0)

当您想将字符串作为命令执行时,请尝试使用eval。这样,您就不会遇到带有空格等字符串的问题。cmd不会重新评估扩展的bash字符串,因此,"hi there"之类的东西会被扩展为两个单独的标记

eval "$bcmd" >> "${BOOST_LOG}" 2>&1

要演示此行为,请考虑以下代码:

cmd='echo "hi there"'
$cmd
eval "$cmd"

哪个输出到:

"hi there"
hi there

令牌"hi there"不会重新评估为带引号的字符串。

答案 2 :(得分:0)

使用一个配额而不是两个配额。

bcmd='./b2 --reconfigure ${PARALLEL} link=static cxxflags=-fPIC install boost.locale.iconv=off boost.locale.posix=off -sICU_PATH=\"${ICU_PREFIX}\" -sICU_LINK=\"${BOOST_ICU_LIBS}\"'

Bash文档指出单个配额不会插值:

  

3.1.2.2 Single Quotes

     

将字符括在单引号(')中可保留引号内每个字符的字面值。即使在单引号之前加反斜杠,也不能在单引号之间引起单引号。

这样,您就可以省略双引号剥离和删除问题,并且字符串将正确传递。如果要保留双引号,则必须更改为它们不保留某些字符的字面值:$'\,除非前面加上\,作为手动状态:

  

3.1.2.3 Double Quotes

     

用双引号(")引起来的字符保留引号内所有字符的文字值,但$`\和启用历史记录扩展后,!。字符$`在双引号中保留其特殊含义(请参见Shell Expansions)。仅当反斜杠后面跟随以下字符之一时,才保留其特殊含义:$`"\或换行符。在双引号中,将删除反斜杠,后跟这些字符之一。没有特殊含义的反斜杠前面的字符将保持不变。可以在双引号内加上双反引号。

在您的示例中,您也忘记在$上加上反斜杠。亚当在这里完美地解释了两者之间的区别:Differences between single and double quota