zsh环境下CMake命令行选项通过变量传递不拆分问题如何解决
问题成因
zsh 和 Bash 对未加引号的变量的默认处理逻辑不同:
- Bash 默认会对未加引号的变量执行 单词拆分(Word Splitting):会根据内置的分隔符变量IFS(默认是空格、制表符、换行符)把变量内容拆分为多个独立参数传递给命令
- zsh 默认关闭了未加引号变量的单词拆分行为:会把整个变量内容作为单个参数传递给命令
你示例中${CMAKE_ARGS}被zsh完整传给cmake后,cmake会把-DUSE_ASSERT=1 -DUSE_DEBUG=0整个字符串识别为USE_ASSERT参数的取值,后续没有匹配到USE_DEBUG的传参,自然就使用了CMakeLists.txt里定义的默认值OFF。
规避方案
推荐按优先级选择以下方案:
方案1:使用数组存储多参数(最通用、最安全)
数组本身就是用来存储多个独立参数的结构,同时兼容zsh和Bash,参数含空格/特殊字符的场景也不会出错,写法如下:
# 定义参数数组 CMAKE_ARGS=(-DUSE_ASSERT=1 -DUSE_DEBUG=0) # 调用时展开数组所有元素 cmake -Bbuild "${CMAKE_ARGS[@]}"
方案2:显式触发zsh的单词拆分
如果一定要用字符串形式存储参数,可以在变量前加=强制zsh对该变量执行单次单词拆分,无需修改全局配置:
export CMAKE_ARGS="-DUSE_ASSERT=1 -DUSE_DEBUG=0" cmake -Bbuild ${=CMAKE_ARGS}
方案3:全局开启单词拆分(不推荐)
可以临时打开zsh的SH_WORD_SPLIT选项,让zsh的行为和Bash保持一致,该操作会影响当前shell会话内所有未加引号变量的处理逻辑,可能引入预期外的副作用:
setopt SH_WORD_SPLIT export CMAKE_ARGS="-DUSE_ASSERT=1 -DUSE_DEBUG=0" cmake -Bbuild ${CMAKE_ARGS} # 用完可以关闭该选项恢复默认行为 unsetopt SH_WORD_SPLIT
内容的提问来源于stack exchange,提问作者Tom de Geus
相关产品推荐
相关产品推荐

