如何让Bash函数输出的带空格参数被set正确识别?
解决Bash命令替换参数分词问题
原代码问题
原代码执行后,set $(func)会将func输出的内容按空格分词,导致"b c"被拆分成两个独立参数:
func() { echo a "b c" } set $(func) echo 1: $1 echo 2: $2 echo 3: $3
执行结果:
1: a 2: b 3: c
修改方案
方案1:用printf输出NUL分隔的参数(推荐,无安全风险)
将echo替换为printf,用NUL字符分隔每个参数(NUL是唯一不会出现在Bash参数中的字符,能彻底避免分词问题):
func() { printf '%s\0' a "b c" }
同时调整set的调用方式,通过readarray读取NUL分隔的内容后再设置参数:
readarray -d '' args < <(func) set -- "${args[@]}"
执行结果:
1: a 2: b c 3:
方案2:输出带引号的字符串并配合eval(仅适用于可控内容)
修改echo语句输出带引号的参数,再用eval解析引号,将"b c"识别为单个参数:
func() { echo 'a' '"b c"' }
调用时使用eval:
eval set $(func)
注意:如果输出内容包含
$、*等特殊字符,eval会执行危险操作,因此仅推荐在内容完全可控的场景使用。
原理说明
Bash的命令替换$(...)会默认按**IFS(内部字段分隔符,默认是空格、制表符、换行)**分割输出内容,所以"b c"中的空格会被当作参数分隔符。用NUL分隔可以绕过这个规则,因为IFS不包含NUL;带引号的方式则是让eval重新解析引号语法,将带空格的内容识别为单个参数。
内容的提问来源于stack exchange,提问作者Wolfgang Rohdewald
相关产品推荐
相关产品推荐

