从CSV文件中提取前两个字段(可能包含逗号或引号)。

3
我有一个包含3个或更多字段的CSV文件,我想提取前两个字段并将它们保存到一个新文件中。请注意,这些字段可能被引号引起来,也可能没有引号,并且可能包含逗号或引号(重复)。我想要精确提取前两个字段(无论是否带引号),并忽略第三个字段和其他字段(如果有的话)。这应该通过命令行完成。目前我有以下命令:
cat 1.csv | awk -F, '{print $1","$2}' > 2.csv

但是如果字段中有逗号,这种方法就不起作用了。
一个字段可能是空的(不包含任何内容,甚至没有引号)。
(我也查看了使用awk忽略CSV文件字段中的逗号,但那里的答案对我来说不起作用) 更新:这个问题不同,因为它要求CSV格式与原始格式相同-无论是带引号还是不带引号的字段。我有一个解决方案,我想提交。

3
你应该提供样本输入CSV和预期输出。 - undefined
一个CSV字段可以包含CSV分隔符、引号和换行符。为了处理这种情况,你可以重新发明轮子并编写另一个CSV解析器(除了已经存在的许多解析器之外),或者你可以使用现有的解析器。我正在使用Ruby自带的解析器,过去也使用过Perl中的解析器。很可能你喜欢的编程语言也有相应的解析器。 - undefined
你能使用一个非标准的CSV命令行工具吗? - undefined
1
@ZachYoung 是的。 - undefined
第二个副本有很多答案,其中许多答案与任何CSV文件都不兼容,但也有很多答案是可以使用的。 - undefined
2个回答

1
给定一个包含带引号字段的输入文件,这些字段中包含嵌入的引号、逗号和换行符。
$ cat file.csv
"foo,""bar""",2,3
1,"foo,bar",3
1,"foo,
bar",3

然后使用GNU awk 5.3或更高版本进行CSV处理:
$ awk --csv -v OFS=',' '{for (i=1; i<=NF; i++) { gsub(/"/,"\"\"",$i); if ($i ~ /[,\n"]/) $i="\"" $i "\"" } print $1, $2}' file.csv
"foo,""bar""",2
1,"foo,bar"
1,"foo,
bar"

CSV格式中需要用引号来保护字段内容,但在读取输入时,这些引号会被去除,因此我们必须在打印之前添加回来,否则输出会变成这样:
$ awk --csv -v OFS=',' '{print $1, $2}' file.csv
foo,"bar",2
1,foo,bar
1,foo,
bar

这不是有效的CSV。
另请参阅使用awk高效解析CSV的最可靠方法

0
GoCSV有select subcommand,它允许我们选择要保留(或排除)指定(或通过管道输入)的CSV中的哪些列。GoCSV已经为许多现代平台预构建。从这个输入CSV开始:
Col1,Col2,Col3
"foo, bar",baz,baker
"Foo, Bar",Baz,baker

您可以直接在文件上调用gocsv。
gocsv select -c 1,2 input.csv

或将CSV导入管道中:
cat input.csv | gocsv select -c 1,2

获取:
Col1,Col2
"foo, bar",baz
"Foo, Bar",Baz

GoCSV总是将第一行解释为标题(并使用标题,以便您可以按名称调用列,如果您喜欢的话)。如果您的原始数据没有标题,您可以使用cap子命令添加一个临时标题,将其传递给select命令,然后将其传递给behead子命令以删除临时标题。
添加cap命令:
echo \"foo, bar\",baz,baker\\n\"Foo, Bar\",Baz,Baker | gocsv cap -names Col1,Col2,Col3

Col1,Col2,Col3
"foo, bar",baz,baker
"Foo, Bar",Baz,Baker

... | gocsv select -c 1,2 | gocsv behead

"foo, bar",baz
"Foo, Bar",Baz

cap子命令具有-default-name选项,但如果不使用-names提供至少一个明确的列名,它将无法正常工作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接