我有一个以竖线 ( |
) 作为分隔符的 CSV 文件,如下所示,我需要在 Unix 中应用合并技术。该文件包含数十万条记录(四个字段),但为了便于阅读,我只给出了五个记录。
field1 |field2 | field3 |field4|
1|abc|def|ghi|
4|ijk|
|lmn|
5||opq|rst|
8|
uvw||xyz|
10|hjg|jsh|nbm|
我希望输出结果为
field1|field2|field3|field4|
1|abc|def|ghi|
4|ijk||lmn|
5||opq|rst|
8|uvw||xyz|
10|hjg|jsh|nbm|
答案1
使用 GNU sed:
sed ':loop /\(.*|\)\{4\}.*/ !{N; s/\n//; b loop}; s/ *| */|/g' file
该命令剖析:
:loop
该:
信号表示我们可以用于分支的标签。 “loop”只是我为标签选择的名称。
/\(.*|\)\{4\}.*/
是一个行选择器正则表达式,匹配包含 4 个管道符号的行,每个管道符号前面允许有零个或多个任意字符 ( .*|
),最后一个管道后面允许有零个或多个任意字符。
!{ ... }
将括号中的命令应用到执行过的任何行不是匹配之前的正则表达式。
N; s/\n//; b loop
N
连接当前行模式空间带有换行符和源文件中的下一行,然后s/\n//
删除换行符并b loop
分支回我们在开始时定义的标签,因此连接的行将再次与正则表达式进行比较。
最后
s/ *| */|/g
将在输出之前应用于模式空间中的任何行。这将删除管道符号周围的所有空格。
答案2
我假设您不想要所有这些空行。
$ cat file
1|abc|def|ghi|
4|ijk|
|lmn|
5||opq|rst|
8|
uvw||xyz|
10|hjg|jsh|nbm|
$ awk -F'|' '{while (NF < 5) {getline nextline; $0 = $0 nextline}}1' file
1|abc|def|ghi|
4|ijk||lmn|
5||opq|rst|
8|uvw||xyz|
10|hjg|jsh|nbm|
问题编辑更新:删除字段分隔符周围的空格
awk -F'[[:blank:]]*[|][[:blank:]]*' -v OFS='|' '
{while (NF < 5) {getline nextline; $0 = $0 nextline}; $1=$1; print}
' file