awk / sed替换换行符

时间:2016-06-27 16:33:33

标签: shell csv awk replace

说明:

我收到了一个CSV文件,其中字段分隔符是管道分类(即|)。 此文件具有预定义数量的字段(例如N)。我可以通过阅读CSV文件的标题来发现N的值,我们可以认为这是正确的。

问题:

某些字段错误地包含换行符,这使得该行看起来比所需的短(即,它有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 个答案:

答案 0 :(得分:6)

$ 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

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

答案 1 :(得分:1)

基于最后一个字段可能包含一个换行符的假设。使用 tac 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 hold 缓冲区中存储无分隔线。
  2. n;获取另一行,因为我们正在向后阅读,这是应该将附加到的行。
  3. x;交换保持缓冲区和模式缓冲区。
  4. H;将模式缓冲区附加到保留缓冲区。
  5. x;将新附加的行交换到模式缓冲区,现在一个缓冲区中有两行。
  6. s/\n/ * /p;用“*”替换中间换行符,现在只有一个更长的行;并打印。
  7. b重新开始,离开代码块。
  8. 使用tac重新反转文件;完成。