如何让awk转义文件分隔符=?properties文件对比异常问题
问题描述
我需要对比并合并两个properties文件的差异,现有以下文件内容:
old1.properties
# comment url=https://test.org/#,https://test.org:id=123
old2.properties
old-key1=value1 old-key3=value3 old-key4=value4
new1.properties
# comment url=#
new2.properties
old-key1=value1 new-key2=value2 old-key3=value3 old-key4=value4
期望合并结果
- 合并old1与new1的结果:
# comment url=https://test.org/#,https://test.org:id=123
- 合并old2与new2的结果:
old-key1=value1 new-key2=value2 old-key3=value3 old-key4=value4
我使用了以下awk命令进行合并:
awk -F= 'NR==FNR {if ($2!="") a[$1]=$2; next} $1 in a {$2=a[$1]} {print $0}' OFS== old.properties new.properties >old_new.txt
但URL中的=被误解析为字段分隔符,得到错误结果:
url=https://test.org,https://test.org:id
请问如何让awk避免将URL内的=当成分隔符?
解决方案
核心问题是原命令用-F=将所有=都视为字段分隔符,但properties文件的键值对中只有第一个=是键与值的分隔符,后续的=属于值的一部分。只需修改awk逻辑,仅以第一个=作为分割依据即可解决。
方法1:通过字符串替换提取键和值
awk 'NR==FNR { # 跳过注释行,仅处理包含=的有效键值行 if ($0 !~ /^#/ && $0 ~ /=/) { # 提取第一个=之前的内容作为键 key = $0; sub(/=.*/, "", key) # 提取第一个=之后的所有内容作为值 val = $0; sub(/^[^=]+=/, "", val) if (val != "") a[key] = val } next } { if ($0 !~ /^#/ && $0 ~ /=/) { key = $0; sub(/=.*/, "", key) # 若键存在于旧文件中,替换当前行的值部分 if (key in a) { sub(/=.*/, "=" a[key]) } } print $0 }' old.properties new.properties > old_new.txt
方法2:用正则限定字段分隔符为第一个=
利用awk支持正则作为字段分隔符的特性,仅匹配第一个=:
awk -F'^([^=]+)=' '{ NR==FNR { if ($2 != "") a[$1] = $2 next } if ($1 in a) { $0 = $1 "=" a[$1] } print $0 }' old.properties new.properties > old_new.txt
两种方法都能精准识别键值对的分隔边界,不会破坏URL中包含的=,最终得到符合预期的合并结果。
内容的提问来源于stack exchange,提问作者user11705123
相关产品推荐
相关产品推荐

