我有一个使用管道字符作为分隔符的文件,因为我假设我的大多数客户端都不会在其数据中使用管道字符。显然我错了,但我通过指定使用管道字符的任何字段需要用双引号括起来补偿这一点。不幸的是,他们还没有这样做,但我不能让他们重新导出他们的文件因为我需要他们的旧数据,所以我需要手动更新他们的旧数据文件以正确引用具有管道字符的字段它
有些线条正确,有16个分隔符,因此有16个字段,而有些线条只有16个字段有18个分隔符。我需要用引号括起第10个字段,如果它有18个分隔符而不是16个。我有一个Linux盒子可供我使用awk,sed,grep等等,并且很想有办法编写脚本这样我就不要不得不手动完成。
只有5和7个分隔符(引用第4个字段)的简化示例输入/输出将是:
# Input
Field 1|Field 2|Field 3|Field 4|Field 5|Field 6
Field 1|Field 2|Field 3|Field | with | pipes|Field 5|Field 6
# Output
Field 1|Field 2|Field 3|Field 4|Field 5|Field 6
Field 1|Field 2|Field 3|"Field | with | pipes"|Field 5|Field 6
# Optional output if it is easier
Field 1|Field 2|Field 3|"Field 4"|Field 5|Field 6
Field 1|Field 2|Field 3|"Field | with | pipes"|Field 5|Field 6
非常感谢任何帮助!
答案 0 :(得分:1)
对于您的样本数据:
sed -i '/\([^|]*|\)\{7\}/{s/\([^|]*|\)/"\1/4;s/\(|[^|]*\)/"\1/6}' inputfile
对于您的真实数据:
sed -i '/\([^|]*|\)\{17\}/{s/\([^|]*|\)/"\1/14;s/\(|[^|]*\)/"\1/16}' inputfile
修改强>
(我在每个示例中添加了一对缺失的大括号,因此第二个s
命令(实际上两者)仅在地址匹配时才会运行。我还删除了-n
和p
删除p
可以消除重复。抱歉错误。)
s
命令之前的部分称为“地址”。它仅选择具有7(或17)个管道字符的行,从而排除s
命令在具有不同管道字符数的行上运行。
//
- 地址的分隔符\(\)
- 分组括号(转义)[^|]*
- 零个或多个(*
)非管道(^|
)字符([]
- 字符列表分隔符)|
- 以及我们感兴趣的竖线字符\{7\}
- 重复七次{command; command}
- 这些大括号分隔了一个命令块,这些命令将在地址匹配时执行 - 地址和大括号一起表现为if
语句及其相关块因此该地址匹配具有七组零个或多个非管道字符的行,每个非管道字符后跟一个管道符。
然后第一个s
命令将第4个(或第14个)管道字符及其前面的非管道字符替换为引号,后跟匹配的字符。
分号是命令分隔符。某些版本的sed
要求使用`sed -e'命令'-e'命令'表单而不是分号,用于多命令单线程脚本。
顺便说一句,s
是一个命令而不是正则表达式的一部分。上面命令中的初始斜杠和s///
命令中的初始斜杠之间的部分之间的部分是正则表达式。
如果您有其他问题,请与我们联系。
第二个s
命令查找第6个(或第16个)管道字符以及跟随它的零个或多个非管道,并将其替换为自身(匹配的字符)和引号。
答案 1 :(得分:1)
KISS。当您使用不同的字段和字段分隔符时,请使用像awk这样的工具,它完全适合工作。
$ cat file
Field 1|Field 2|Field 3|Field 4|Field 5|Field 6
Field 1|Field 2|Field 3|Field | with | pipes|Field 5|Field 6
$ awk -F"|" 'NF>6{$4="\042"$4 ; $(NF-2)=$(NF-2)"\042";}1' OFS="|" file
Field 1|Field 2|Field 3|Field 4|Field 5|Field 6
Field 1|Field 2|Field 3|"Field | with | pipes"|Field 5|Field 6
如上所述,如果字段数超过6(即NF> 6),则在第4个字段以及最后第2个字段中添加双引号(\ 042)。 (或根据您的数据进行相应更改。)
无需使用复杂的正则表达式。