如何在Bash中保留换行符导入多行关联数组?
解决Bash关联数组导入时换行符丢失的问题
这个问题我之前踩过坑,本质是Bash处理换行符和特殊字符的逻辑导致的,我给你拆解清楚怎么解决!
问题分析
你尝试的两种方法都没能保留换行符,核心原因:
- 用
declare -p导出数组时,Bash会自动把值里的换行符替换成空格,导出的文件里已经没有换行信息了; - 用
echo写入文件时,虽然文件里能看到换行,但source解析时,Bash会把这些换行当成命令中的空白分隔符,最终把值合并成一行。
解决方案一:用printf %q自动转义特殊字符
这个方法最省心可靠,%q会把变量中的所有特殊字符(包括换行、引号、空格等)自动转义成Bash能正确解析的格式,确保source后完全保留原始内容。
步骤如下:
- 先正确定义带换行的关联数组(用
$'...'语法来识别转义字符):
declare -A MOCK_RETURNS=( ['/usr/local/bin/docker']="" ['/usr/local/bin/docker history']=$'IMAGE CREATED AT CREATED BY SIZE COMMENT\ncf0f3ca922e0 -10-18T20:48:51+02:00 /bin/sh -c #(nop) CMD ['\''/bin/bash'\''] 0 <missing>\n2019-10-18T20:48:51+02:00 /bin/sh -c mkdir -p /run/systemd && echo '\''do…'\'' 7' )
- 用
printf生成可被source的文件:
printf 'declare -A MOCK_RETURNS=(%s)\n' "$( for key in "${!MOCK_RETURNS[@]}"; do printf " ['%s']=%q" "$key" "${MOCK_RETURNS[$key]}" done )" > mockResponse
- 验证效果:
source mockResponse # 用printf直接输出原始内容(无需转义) printf "%s" "${MOCK_RETURNS['/usr/local/bin/docker history']}" # 或者用echo -e解析转义的换行符 echo -e "${MOCK_RETURNS['/usr/local/bin/docker history']}"
解决方案二:手动用单引号包裹值并转义内部引号
如果你想手动生成文件,可以用单引号包裹带换行的值,同时把值内部的单引号转义为'\'',并且用<<'EOF'避免Bash提前解析内容:
cat > mockResponse <<'EOF' declare -A MOCK_RETURNS=( ['/usr/local/bin/docker']="" ['/usr/local/bin/docker history']='IMAGE CREATED AT CREATED BY SIZE COMMENT cf0f3ca922e0 -10-18T20:48:51+02:00 /bin/sh -c #(nop) CMD ['\''/bin/bash'\''] 0 <missing> 2019-10-18T20:48:51+02:00 /bin/sh -c mkdir -p /run/systemd && echo '\''do…'\'' 7' ) EOF
之后直接source mockResponse就能保留换行符,输出时用printf或echo -e即可看到换行效果。
内容的提问来源于stack exchange,提问作者El Gohr
相关产品推荐
相关产品推荐

