我的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
有什么区别?我希望能够使用第二种方法,以便可以在运行命令之前将命令传递给另一个函数。
答案 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文档指出单个配额不会插值:
将字符括在单引号(
'
)中可保留引号内每个字符的字面值。即使在单引号之前加反斜杠,也不能在单引号之间引起单引号。
这样,您就可以省略双引号剥离和删除问题,并且字符串将正确传递。如果要保留双引号,则必须更改为它们不保留某些字符的字面值:$
,'
和\
,除非前面加上\
,作为手动状态:
用双引号(
"
)引起来的字符保留引号内所有字符的文字值,但$
,`
,\
和启用历史记录扩展后,!
。字符$
和`
在双引号中保留其特殊含义(请参见Shell Expansions)。仅当反斜杠后面跟随以下字符之一时,才保留其特殊含义:$
,`
,"
,\
或换行符。在双引号中,将删除反斜杠,后跟这些字符之一。没有特殊含义的反斜杠前面的字符将保持不变。可以在双引号内加上双反引号。
在您的示例中,您也忘记在$
上加上反斜杠。亚当在这里完美地解释了两者之间的区别:Differences between single and double quota