GNU sed追加(a)命令异常清空文件,请求排查解决
问题分析与解决方案
你的脚本出现文件清空、原内容丢失的问题,核心原因有三个:
- 使用
-n选项抑制了sed的默认输出,导致-i原地编辑时,只有追加的内容被写入文件,原内容全部丢失 MAGIC_STRING中的!会触发bash历史扩展,导致sed正则匹配失效0,/^$MAGIC_STRING/!b逻辑会跳过第一个匹配行之后的所有内容,进一步加剧内容丢失
以下是符合需求的修正方案:
修正后的脚本
MAGIC_STRING='#!#%%%===!!' # 转义正则特殊字符,避免匹配错误,同时处理bash历史扩展问题 ESCAPED_MAGIC=$(printf '%s\n' "$MAGIC_STRING" | sed 's/[^^$.*+?()|[\]{}!]/\\&/g') # 用$''定义变量,确保换行符被正确解析 DNS_REGISTRY=$'tomato IN A 222.88.1.2' file=/home/anyuser/file.txt # 原地修改文件,同时保留所有原内容,仅在第一个MAGIC_STRING行后追加内容 sed -i -e "0,/^$ESCAPED_MAGIC/{//a $DNS_REGISTRY}" "$file" # 获取修改后的完整文件内容 appended_string=$(cat "$file") echo "APPENDED: $appended_string" [[ -n "$appended_string" ]] && echo "Modified file"
关键调整说明
- 转义特殊字符:通过
sed命令转义MAGIC_STRING中的正则特殊字符(如!、%等),确保sed能精准匹配目标行,同时避免bash历史扩展干扰 - 变量定义优化:用
$'...'定义DNS_REGISTRY,让shell正确解析换行符,保证追加内容格式正确 - 移除
-n选项:让sed默认输出所有行,保留原文件全部内容 - 调整sed逻辑:
0,/^$ESCAPED_MAGIC/{//a $DNS_REGISTRY}仅在第一个匹配到的MAGIC_STRING行下方追加内容,其他行正常输出
可选:直接输出修改内容到stdout
如果需要sed直接将修改后的内容输出到stdout(同时修改文件),可以用临时文件避免截断问题:
MAGIC_STRING='#!#%%%===!!' ESCAPED_MAGIC=$(printf '%s\n' "$MAGIC_STRING" | sed 's/[^^$.*+?()|[\]{}!]/\\&/g') DNS_REGISTRY=$'tomato IN A 222.88.1.2' file=/home/anyuser/file.txt temp_file=$(mktemp) # 输出修改后的内容到stdout,同时写入临时文件 sed -e "0,/^$ESCAPED_MAGIC/{//a $DNS_REGISTRY}" "$file" | tee "$temp_file" # 替换原文件 mv "$temp_file" "$file" appended_string=$(cat "$file") echo "APPENDED: $appended_string" [[ -n "$appended_string" ]] && echo "Modified file"
测试效果
原文件内容:
#!#%%%===!! tomato IN A 222.88.1.2 #!#%%%===!!
执行脚本后,文件内容变为:
#!#%%%===!! tomato IN A 222.88.1.2 tomato IN A 222.88.1.2 #!#%%%===!!
同时appended_string会包含修改后的完整文件内容,echo "Modified file"会正常执行。
内容的提问来源于stack exchange,提问作者d3vr10
相关产品推荐
相关产品推荐

