解析一个包含逗号字段的CSV文件,使用awk。

19

我必须使用awk从CSV文件中打印出4个不同的列。问题是字符串以$ x,xxx.xx的格式呈现。当我运行常规的awk命令时遇到问题。

awk -F, {print $1} testfile.csv 

我的输出结果最终看起来像

307.00
$132.34
30.23
我做错了什么。

"$141,818.88","$52,831,578.53","$52,788,069.53" 这大概是输入内容。我需要解析的文件有90000行,大约40列,其中部分包含上述内容。如果我让你误解了,请原谅。

如果输入是"$307.00","$132.34","$30.23",我希望输出在一个

中。
$307.00
$132.34
$30.23

提供一个样本输入,我会看看你能输出什么。 - JUST MY correct OPINION
好的,提供根本不接近实际输入的示例输入是毫无意义的。给我一个代表性的样本输入。 - JUST MY correct OPINION
可能是这个问题的重复:使用awk解析csv并忽略字段内的逗号。该问题的答案中有一个链接,指向一个处理CSV文件的AWK脚本。但是通常最好使用专门设计用于CSV文件或Python或Perl模块的工具。 - Dennis Williamson
我希望我可以使用其他工具。但是我必须使用 awk 来解析它。 - Dudusmaximus
1
请提供一个输入示例和期望的成对输出。 - Dr. belisarius
@Dudusmaximus:我之前也遇到过这个问题,但是通过一些字段分隔符的技巧,我很优雅地解决了它。请看我的回答 - SiegeX
4个回答

20

有趣的是,我不久前也遇到了这个问题,并保留了代码来解决它。你几乎已经做到了,但你需要在字段分隔符上做些小技巧。

awk -F'","|^"|"$' '{print $2}' testfile.csv 

输入

# cat testfile.csv
"$141,818.88","$52,831,578.53","$52,788,069.53"
"$2,558.20","$482,619.11","$9,687,142.69"
"$786.48","$8,568,159.41","$159,180,818.00"

输出

# awk -F'","|^"|"$' '{print $2}' testfile.csv
$141,818.88
$2,558.20
$786.48

请注意,“第一个”字段实际上是$2,因为使用了字段分隔符^"。如果你问我,这只是为了让这个简短的一行代码更加易读易懂。

2
非常流畅!在此方法的基础上,以下是一种处理烦人的空第一个字段的方法,使字段编号像往常一样从$1开始:awk -F'","|^"|"$' '{sub("^\"","")} {print $1}' - Kamal
3
如果不是每个字段都使用引号,这个方法还有效吗?比如 ANAD,2.69,183.38,446.31,2.90,41.46,"Technology","Semiconductor - Integrated Circuits",,2.34,40.10%,-51.88%,33.17%,-16.46%,"Anadigics, Inc.",3.18%,"USA",,$1=="ANAD" 时,我想仅获取位置 $15 中的 "Anadigics, Inc." - Marcos
@Marcos 不好意思,它不会。但是,你只需要使用逗号作为字段分隔符,所以可以使用-F',' - SiegeX
1
只有在我使用 stock="ANAD"; awk -F',' '$1=="$stock" {print $15}' AllStocks.csv 时才会返回 "Anadigics",但还是谢谢。 - Marcos
我正在使用@Kamal的答案,并带有-F'","'。然而,它没有你和Kamal提到的任何问题。即空的第一个字段,杂乱的双引号等。你能解释一下你的答案是如何工作的吗?我的CSV文件类似于fieldA,fieldB,“fieldC1,fieldC2” - Tan Yu Hau Sean
显示剩余2条评论

8
我认为您的意思是想将输入拆分成CSV字段,同时不受双引号内逗号的干扰。如果是这样的话...

首先,使用","作为字段分隔符,就像这样:

awk -F'","' '{print $1}'

但是你仍然会在$1的开头(以及最后一个字段的结尾)留下一个多余的双引号。通过使用gsub去掉引号,如下:

awk -F'","' '{x=$1; gsub("\"","",x); print x}'

结果:

echo '"abc,def","ghi,xyz"' | awk -F'","' '{x=$1; gsub("\"","",x); print x}'

abc,def

哇,谢谢你,这个完美地解决了我的问题。我已经卡在这里两天了。 - Dudusmaximus
太好了!请确保点击绿色的勾号,表示这个问题已经解决了。 - Kamal
2
你可以不需要使用gsub()和额外的变量来完成这个任务。关键是要使用多个字段分隔符-F'","|^"|"$'(请参考我的回答)。 - SiegeX

3
为了让awk处理包含字段分隔符的带引号字段,您可以使用我编写的一个名为csvquote的小脚本。它会暂时将有问题的逗号替换为不可打印字符,然后在管道末尾恢复它们。就像这样:
csvquote testfile.csv | awk -F, {print $1} | csvquote -u

这也适用于任何其他UNIX文本处理程序,例如cut:
csvquote testfile.csv | cut -d, -f1 | csvquote -u

你可以在这里获取csvquote代码:https://github.com/dbro/csvquote

很高兴我找到了这个好用的工具!我终于找到了一种可靠的方法来解析在没有Select into outfile权限的服务器上的mysqldump输出。 - Michael Blood

1
数据文件:
$ cat data.txt
"$307.00","$132.34","$30.23"

AWK脚本:
$ cat csv.awk
BEGIN { RS = "," }
{ gsub("\"", "", $1);
  print $1 }

执行:

$ awk -f csv.awk data.txt
$307.00
$132.34
$30.23

OP在他的问题中表述不够清晰,但是他的问题出现在字段本身带有逗号的情况下。请参考我的答案以解决这个问题。 - SiegeX
我接受了他的输入并生成了他想要的输出。如果他想要其他内容,那他应该提出请求。;) - JUST MY correct OPINION

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