我有 CSV 文件,其中很少有记录的数据移动到新行:
例子:
ABCD,1234,QWER
ASDF
,2345,VGFT
"ASDF,12",1212,ASDR
1234,ZXCV,ERTT
输出结果应该是:
ABCD,1234,QWER
ASDF,2345,VGFT
"ASDF,12",1212,ASDR
1234,ZXCV,ERTT
有没有办法连接第二列和第三列?
答案1
这是一个天真的黑客,适用于给定的数据:
$ awk -F, 'NF != 3 { printf("%s",$0); getline } 1' file.csv
ABCD,1234,QWER
ASDF,2345,VGFT
1234,ZXCV,ERTT
它的作用是将awk
文件解析为逗号分隔的数据集。如果一行不正好有三个字段 ( NF != 3
),则按原样输出迄今为止已读取的行的位,不带尾随换行符,并读取下一行。 Final1
是 的缩写{ print }
并将打印所有行。
如果第一个块已触发,则最后的1
/print
将导致断线的其余部分在 输出的末尾输出printf
。
其变体为sed
:
$ sed -E '/^[^,]+,[^,]+,[^,]+$/!{ N; s/\n//; }' file.csv
ABCD,1234,QWER
ASDF,2345,VGFT
1234,ZXCV,ERTT
同样,如果线路以示例数据中所示的其他方式断开,则这可能不起作用。
该sed
脚本的作用是使用正则表达式测试每一行^[^,]+,[^,]+,[^,]+$
。如果匹配,我们就有了一条看起来应该做的行;由逗号以外的字符组成的三个字段,以逗号分隔。如果那是不是在这种情况下,下一行将被附加到当前行的末尾,并且插入在两行之间的N
换行符将被删除。sed
该sed
代码遵循与 代码相同的逻辑awk
,如果当前行有故障,则它会追加下一行数据。
答案2
著名的sed
一句台词的一种变体:
$ sed -e :a -e '$!N;s/\n[[:blank:]]*,/,/;ta' -e 'P;D' file.csv
ABCD,1234,QWER
ASDF,2345,VGFT
"ASDF,12",1212,ASDR
1234,ZXCV,ERTT
答案3
通过混合 shell 变量,我们可以在 GNU 中执行此操作,sed
如下所示:
nF='[^,]*'; # a normal unquoted csv field
qF='"[^"]*"'; # a quoted csv field
F="\($qF\|$nF\)"; # a csv field
ok="$F,$F,$F\$"; # a csv record with exactly 3 fields
# ok="\($F,\)\{2\}$F\$"; # an equivalent way to write out the regex for an ok csv record
sed -e "
:a;/$ok/b
N;s/\n//;ba
" input.csv
输出
ABCD,1234,QWER
ASDF,2345,VGFT
"ASDF,12",1212,ASDR
1234,ZXCV,ERTT
作为
- 使用要在 sed 中使用的 shell 变量的混合来构建 csv 的语法。
- 假设一条csv记录不超过3个字段。
- 首先检查 csv 记录是否正常,也就是说,它正好有 3 个字段。在这种情况下,只需打印该记录并读取下一条记录即可。
- OTW,意思是,在当前 csv 记录中找到的字段少于 3 个,我们通过命令附加下一行
N
,然后删除连接器 a\n
,并使用此修改后的模式空间,分支到 sed 代码的顶部。