代码之家  ›  专栏  ›  技术社区  ›  user2340612

Awk/sed替换换行符

  •  5
  • user2340612  · 技术社区  · 10 年前

    简介:

    我收到一个CSV文件,其中字段分隔符是管道特征(即。, | ). 此文件具有预定义的字段数(例如 N ). 我可以发现 N 通过读取CSV文件的头,我们可以假设它是正确的。

    问题:

    有些字段错误地包含换行符,这使得行看起来比要求的短(即 M 字段,使用 M < N ).

    我需要创建一个 sh 脚本(不是 bash )来修理这些线路。

    尝试的解决方案:

    我尝试创建以下脚本以尝试修复文件:

    if [ $# -ne 1 ]
    then
        echo "Usage: $0 <filename>"
        exit
    fi
    
    # get first line
    first_line=$(head -n 1 $1)
    
    # get number of fields
    num_separators=$(echo "$first_line" | tr -d -c '|' | awk '{print length}')
    
    cat $1  | awk -v numFields=$(( num_separators + 1 )) -F '|' '
    {
        totRecords = NF/numFields
        # loop over lines
        for (record=0; record < totRecords; record++) {
            output = ""
            # loop over fields
            for (i=0; i<numFields; i++) {
                j = (numFields*record)+i+1 
                # replace newline with question mark
                sub("\n", "?", $j)
                output = output (i > 0 ? "|" : "") $j 
            }
            print output
        }
    }
    '
    

    然而,换行符仍然存在。 我怎样才能解决这个问题?

    CSV示例:

    FIRST_NAME|LAST_NAME|NOTES
    John|Smith|This is a field with a
    newline
    Foo|Bar|Baz
    

    预期产出:

    FIRST_NAME|LAST_NAME|NOTES
    John|Smith|This is a field with a * newline
    Foo|Bar|Baz
    
    * I don't care about the replacement, it could be a space, a question mark, whatever except a newline or a pipe (which would create a new field)
    
    2 回复  |  直到 10 年前
        1
  •  7
  •   Ed Morton    10 年前
    $ cat tst.awk
    BEGIN { FS=OFS="|" }
    NR==1 { reqdNF = NF; printf "%s", $0; next }
    { printf "%s%s", (NF < reqdNF ? " " : ORS), $0 }
    END { print "" }
    
    $ awk -f tst.awk file.csv
    FIRST_NAME|LAST_NAME|NOTES
    John|Smith|This is a field with a newline
    Foo|Bar|Baz
    

    如果这不是你想要的,那么编辑你的问题,以提供更具代表性的样本输入和相关输出。

        2
  •  1
  •   agc Blair Houghton    10 年前

    基于最后一个字段可能包含一个换行符的假设。使用 战术计算机 sed标准 :

    tac file.csv | sed -n '/|/!{h;n;x;H;x;s/\n/ * /p;b};p' | tac 
    

    输出:

    FIRST_NAME|LAST_NAME|NOTES
    John|Smith|This is a field with a * newline
    Foo|Bar|Baz
    

    工作原理。反向读取文件, sed标准 没有向前引用更容易。如果行没有“|”分隔符, /|/! ,在花括号中运行代码块 {}; ,否则只是 p 打印行。代码块:

    1. h; 将无分隔符的行存储在 sed 持有 缓冲器
    2. n; 获取另一行,因为我们正在反向读取,这是应该附加的行 .
    3. x; 交换保持缓冲区和模式缓冲区。
    4. H; 附加模式缓冲区 保持缓冲区。
    5. x个; 将新附加的行交换到模式缓冲区,现在一个缓冲区中有两行。
    6. s/\n/ * /p; 用“*”替换中间换行符,现在只有一个 比较长的 线并打印。
    7. b 重新开始,留下代码块。

    使用重新还原文件 tac ; 完成。