如何用awk将含多行字段的CSV记录转为单行并替换换行符
问题描述
需要处理CSV文件,将每条记录输出为单行,同时把数据中的所有换行符替换为临时占位符<br>。示例记录如下(每条含12个字段,第9个字段为多行脚本):
"Chvro"|"SCRIPT.CHANGE.PASSWORD.1"|0|"script.change.password.1"|"ShellScriptTemplate"|"CLOBPART"|||"import com.company.dto.exception.UCMException; import com.jscape.inet.ssh.SshException; try { logger.info(""Send passwd command""); session.sendWait(""passwd ""+userId, "".*exist.*"", true, timeout); } catch (SshException e) { logger.error(""Send passwd command failed"", e); throw new UCMException(""Send passwd command failed"", e); } try { logger.info(""Send old password""); session.sendWait(oldPassword, "".*[N|n]ew.*"", true, timeout); } catch (SshException e) { logger.error(""Send old password failed"", e); throw new UCMException(""Send old password failed"", e); } try { logger.info(""Send new password""); session.sendWait(newPassword, "".*[R|r]e-enter.*"", true, timeout); } catch (SshException e) { logger.error(""Send new password failed"", e); throw new UCMException(""Send new password failed"", e); } try { logger.info(""Send confirm new password""); session.sendWait(newPassword, "".*success.*"", true, timeout); } catch (SshException e) { logger.error(""Confirm new password failed"", e); throw new UCMException(""Confirm new password failed"", e); } logger.info(""Change password succeed""); "||"N"|
当前使用的awk命令无法完全替换换行符,且希望避免硬编码字段位置(如$9),实现全记录字段的换行符替换:
awk -v FS='|' -v OFS='|' -v ORS='\n' -v fields=12 '{f+=NF; str=(str?str "<br>": "") $0} f>=fields{gsub(/\n/, "<br>", str); print str; str=""; f=0}' myinput.csv
问题分析
原命令存在两个核心问题:
- 拼接记录时错误地用
<br>连接各行,而非保留原始换行符后统一替换,导致gsub(/\n/, "<br>")实际未生效(awk读取的$0不包含行尾换行符)。 - 通过累计字段数判断记录结束的方式不准确:多行字段会被拆分为多个awk行,每行的
NF为1,导致累计字段数远超目标值,可能提前或延迟处理记录。
解决方案
推荐使用识别CSV双引号包裹规则的方式处理,无需依赖字段数,更准确适配跨行字段:
awk -v OFS='|' ' { # 统计当前行的双引号数量,跟踪是否处于字段内部 quote_count += gsub(/"/, "&") # 拼接当前行到记录,保留原始换行 record = record $0 "\n" # 双引号数量为偶数时,说明一条完整记录结束(字段内部的双引号已转义为"",不影响计数) if (quote_count % 2 == 0) { # 移除最后多余的换行符 sub(/\n$/, "", record) # 将所有换行符替换为<br> gsub(/\n/, "<br>", record) # 输出单行记录 print record # 重置变量,准备处理下一条记录 record = "" quote_count = 0 } } ' myinput.csv
原理说明:
- CSV规范中,含换行的字段必须用双引号包裹,字段内部的双引号需转义为两个双引号(
"")。 - 通过统计双引号总数的奇偶性,判断是否完成一条记录的读取:偶数表示所有字段的双引号都已闭合,记录完整。
- 收集完整记录后,统一替换所有换行符为
<br>,确保输出为单行。
若仍希望基于字段数处理(需确保字段无嵌套|),可修正原命令的拼接逻辑:
awk -v FS='|' -v target_fields=12 ' { # 保留原始换行,拼接当前行 str = str $0 "\n" field_count += NF # 累计字段数达到目标时处理 if (field_count >= target_fields) { sub(/\n$/, "", str) gsub(/\n/, "<br>", str) print str str = "" field_count = 0 } } ' myinput.csv
内容的提问来源于stack exchange,提问作者user10931326
相关产品推荐
相关产品推荐

