UNIX下对比两平面文件指定字段(数值格式不同)求助
嘿,这个金额格式不统一的对比问题确实有点棘手,不过咱们先把两边的金额字段统一成相同格式,之后对比就轻松多啦!结合你已经用cut提取好目标字段的情况,给你几个实用的解决方案:
方法1:用awk统一金额格式后对比(最靠谱的数值处理方式)
因为awk可以直接把金额字符串转成数值,自动处理各种格式差异(比如-0、1、1.2这些),再统一格式化为两位小数,完美匹配文件2的格式。
重要提醒:你用cut -d '|' -f 1-45,56,67-174提取后,原来的第56位金额字段现在变成了cut结果里的第46位(前面1-45是45个字段),下面的命令都是基于这个位置来的。
首先,你可以把两个cut后的文件统一格式后存成临时文件,再用diff对比:
# 处理cut后的文件1,统一金额为两位小数 awk -F'|' '{ normalized_amt = sprintf("%.2f", $46 + 0) # 重新拼接整行,替换金额字段 line = $1 for (i=2; i<=NF; i++) { if (i == 46) line = line "|" normalized_amt else line = line "|" $i } print line }' cut_file1 > normalized_file1 # 同样处理cut后的文件2 awk -F'|' '{ normalized_amt = sprintf("%.2f", $46 + 0) line = $1 for (i=2; i<=NF; i++) { if (i == 46) line = line "|" normalized_amt else line = line "|" $i } print line }' cut_file2 > normalized_file2 # 对比两个格式化后的文件 diff normalized_file1 normalized_file2
如果不想生成临时文件,可以用shell的进程替换直接对比:
diff <(awk -F'|' '{ normalized_amt = sprintf("%.2f", $46 + 0) line = $1 for (i=2; i<=NF; i++) { if (i == 46) line = line "|" normalized_amt else line = line "|" $i } print line }' cut_file1) <(awk -F'|' '{ normalized_amt = sprintf("%.2f", $46 + 0) line = $1 for (i=2; i<=NF; i++) { if (i == 46) line = line "|" normalized_amt else line = line "|" $i } print line }' cut_file2)
方法2:直接用awk对比并输出不匹配记录
如果你的两个文件是按某个唯一关键字(比如第一个字段)一一对应的,这个方法能直接输出不匹配的记录,比diff更直观:
awk -F'|' 'NR==FNR { # 先读取第一个文件,把格式化后的整行存在数组里,用第一个字段当索引 normalized_amt = sprintf("%.2f", $46 + 0) line = $1 for (i=2; i<=NF; i++) { if (i == 46) line = line "|" normalized_amt else line = line "|" $i } records[$1] = line next } { # 读取第二个文件,格式化后和第一个文件的记录对比 normalized_amt = sprintf("%.2f", $46 + 0) line = $1 for (i=2; i<=NF; i++) { if (i == 46) line = line "|" normalized_amt else line = line "|" $i } if (records[$1] != line) { print "⚠️ Mismatch for key " $1 ":" print "File1: " records[$1] print "File2: " line print "-------------------------" } }' cut_file1 cut_file2
方法3:用sed做字符串替换统一格式(适合简单场景)
如果你确定金额格式只有你提到的几种(比如整数、一位小数、-0),也可以用sed做字符串替换来统一格式,不过这种方法不如awk的数值处理可靠,万一有特殊格式容易出错:
# 处理文件1的cut结果:把整数补成.00,一位小数补成两位,-0/-0.0换成0.00 sed -E ' s/([^|]+)\|(-?[0-9]+)(\|)/\1|\2.00\3/g; s/([^|]+)\|(-?[0-9]+\.[0-9])(\|)/\1|\20\3/g; s/([^|]+)\|-0(\.0?)?(\|)/\1|0.00\3/g ' cut_file1 > normalized_file1 # 文件2的格式已经是两位小数,直接用原cut结果或者也做个兜底处理 sed -E 's/([^|]+)\|(-?[0-9]+\.[0-9]{2})(\|)/\1|\2\3/g' cut_file2 > normalized_file2 # 对比 diff normalized_file1 normalized_file2
记得替换命令里的cut_file1和cut_file2为你实际的文件名哦!
内容的提问来源于stack exchange,提问作者D1vyA
相关产品推荐
相关产品推荐

