如何不使用eval将带嵌套引号的字符串转为Bash数组?
不使用eval实现带引号字符串的正确数组拆分
先看示例代码里的问题:
input="a b '1 2 3' c" arr=($input); printf '%s|' "${arr[@]}" # 输出:a|b|'1|2|3'|c| eval "arr=($input)"; printf '%s|' "${arr[@]}" # 输出:a|b|1 2 3|c|
直接执行arr=($input)时,Bash会按空格拆分所有内容,把带引号的'1 2 3'拆成了'1、2、3'三个元素;而eval能正确识别引号,把1 2 3当作单个元素,但eval存在安全风险,容易被注入恶意命令。
下面提供两种不用eval的实现方式:
方法一:用read循环读取xargs处理后的元素
input="a b '1 2 3' c" arr=() # xargs自动解析引号,将每个元素单独输出为一行,再循环读取到数组 while IFS= read -r item; do arr+=("$item") done < <(xargs printf '%s\n' <<< "$input") printf '%s|' "${arr[@]}" # 输出:a|b|1 2 3|c|
方法二:用readarray(mapfile)批量读取
如果你的Bash版本在4.0及以上,可以用更简洁的readarray(别名mapfile):
input="a b '1 2 3' c" # xargs解析引号后按行输出,readarray直接将每行内容存入数组 readarray -t arr < <(xargs printf '%s\n' <<< "$input") printf '%s|' "${arr[@]}" # 输出:a|b|1 2 3|c|
原理说明
xargs会按照Shell的分词规则解析输入字符串,自动识别单引号、双引号包裹的内容,将其视为单个元素;随后用printf '%s\n'把每个元素输出为单独一行,再通过进程替换< <(...)传递给read或readarray,最终把每个元素正确存入数组,完全规避了eval的安全隐患。
内容的提问来源于stack exchange,提问作者Marcus Whybrow
相关产品推荐
相关产品推荐

