You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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
问题分析

原命令存在两个核心问题:

  1. 拼接记录时错误地用<br>连接各行,而非保留原始换行符后统一替换,导致gsub(/\n/, "<br>")实际未生效(awk读取的$0不包含行尾换行符)。
  2. 通过累计字段数判断记录结束的方式不准确:多行字段会被拆分为多个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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 12:31:10