那么,您想用awk 解析一个CSV 文件并只修改一部分列?
首先,解析 CSV 字段并不像在分隔符上拆分(,,或者在您的情况下为 ;)那么简单,因为在引用值时必须避免拆分。 awk 的配方在 excellent answer by @EdMorton 中给出,如果您使用 GNU awk,最优雅的方法是使用 FPAT:
awk -v FPAT='[^;]*|"[^"]+"' -v OFS=';' '...'
(对于其他awks和一些特殊情况,请参阅引用的答案。)
现在回到你的程序。 gsub ERE 参数的正确语法是 /pattern/ 或 "pattern",但不能同时使用两者(例如 "/pattern/")。
这意味着您必须按如下方式替换:
gsub("/\&\;/","\&",$3) --> gsub(/&/, "\\&", $3)
gsub("/\·\;/", " ",$3) --> gsub(/·/, " ", $3)
gsub("/\â\;/", "a",$3) --> gsub(/â/, "a", $3)
gsub("/\é\;/", "e",$3) --> gsub(/é/, "e", $3)
另请注意,在 ERE 正则表达式部分,& 和 ; 不必转义,但在替换字符串 & 中需要转义(\ 也需要转义)。
此外,如果只修改$3 列,则不需要for 循环。但是,如果您真的想修改以$3 开头并以最后一个$NF 结尾的列范围,则需要在每个gsub 调用中使用$i,而不是$3。
已修复,您的 awk 程序如下所示:
awk -v FPAT='[^;]*|"[^"]+"' -v OFS=';' '{
for (i=3; i<=NF; i++) {
gsub(/&/, "\\&", $i)
gsub(/·/, " ", $i)
gsub(/â/, "a", $i)
gsub(/é/, "e", $i)
gsub(/#/, " ", $i)
}
print
}' file.csv
(末尾的print 确保打印每一行。)
应用于您的示例(并转换为单行):
$ echo '32602;1;"Wet & Dry 5029";2663,2662' | awk -v FPAT='[^;]*|"[^"]+"' -v OFS=';' '{for (i=3;i<=NF;i++) {gsub(/&/,"\\&",$i); gsub(/·/," ",$i); gsub(/â/,"a",$i); gsub(/é/,"e",$i); gsub(/#/," ",$i)}; print}'
32602;1;"Wet & Dry 5029";2663,2662
在 cmets 中进行其他故障排除后,您的问题的解决方案似乎不是替换某些特定列中的那些 HTML 实体,而是在完整文件中替换它们,因为您的 CSV 文件似乎格式不正确,因此后续处理器无法解析它(可能是由于未引用 ;s)。
您可以使用简单的sed 命令替换您指定的所有 HTML 实体,例如:
sed -e 's/&/\&/g' -e 's/·/ /g' -e 's/â/a/g' -e 's/é/e/g' -e 's/#/ /g' file