如何在Bash中通过变量向命令行程序传递空字符串?
Bash传递可能为空的字符串参数到命令行程序的问题
需要从Bash向命令行程序传递存储在变量中的可能为空的字符串,以下是用于测试的C++最小示例:
// Compile with g++ main.cpp -o soexec #include <iostream> int main(int argc, char** argv) { // 打印程序收到的参数 for(size_t ind = 1 ; ind < argc; ++ind) std::cout << " argv[" << ind << "]={" << argv[ind] << "}" << std::endl; // 实际业务代码位置 return EXIT_SUCCESS; }
测试情况
正常工作的场景
直接传递空字符串,或用双引号包裹变量传递时,结果符合预期:
./soexec --paramName ""
输出:
argv[1]={--paramName} argv[2]={} # 得到了想要的空字符串
EMPTY_VARIABLE= ./soexec --paramName "${EMPTY_VARIABLE}"
输出:
argv[1]={--paramName} argv[2]={} # 得到了想要的空字符串
出现问题的场景
当把所有参数存入单个字符串变量后直接展开时,空字符串参数会丢失:
VARIABLE_NAME= ARGS="--paramName $VARIABLE_NAME" ./soexec $ARGS
输出:
argv[1]={--paramName} # 没有argv[2],空参数被忽略
尝试给变量添加引号后,传递的会是包含引号的非空字符串:
VARIABLE_NAME=\"\" ARGS="--paramName $VARIABLE_NAME" ./soexec $ARGS
输出:
argv[1]={--paramName} argv[2]={""} # 字符串非空,包含引号
解决方案
方法1:使用Bash数组存储参数
Bash数组可以精准保留每个参数的边界,包括空字符串,是最安全可靠的方式:
VARIABLE_NAME= ARGS=(--paramName "$VARIABLE_NAME") ./soexec "${ARGS[@]}"
执行后输出符合预期:
argv[1]={--paramName} argv[2]={}
"${ARGS[@]}"会将数组中的每个元素作为独立参数传递,空元素会被完整保留为一个空字符串参数。
方法2:使用eval(谨慎使用)
如果必须用单个字符串存储参数,可以借助eval解析参数,但仅在参数内容完全可控时使用,避免命令注入风险:
VARIABLE_NAME= ARGS="--paramName \"$VARIABLE_NAME\"" eval ./soexec $ARGS
执行后同样能得到预期的空字符串参数。
核心原理
Bash对未加引号的变量展开时,会执行单词拆分和路径扩展,空字符串会被直接忽略;而用双引号包裹变量("${VAR}")或数组展开"${ARR[@]}"时,会保留参数的原始边界,包括空字符串。
内容的提问来源于stack exchange,提问作者GabrielGodefroy
相关产品推荐
相关产品推荐

