我需要在逗号分隔值文件中删除2列。 请考虑csv文件中的以下行:
"abc@xyz.com,www.example.com",field2,field3,field4
"def@xyz.com",field2,field3,field4
现在,我想要的结果是:
"abc@xyz.com,www.example.com",field4
"def@xyz.com",field4
我使用了以下命令:
awk 'BEGIN{FS=OFS=","}{print $1,$4}'
但是引号内的嵌入式逗号会产生问题,以下是我得到的结果:
"abc@xyz.com,field3
"def@xyz.com",field4
现在我的问题是如何让awk忽略双引号内的“?”?
答案 0 :(得分:35)
从GNU awk手册(http://www.gnu.org/software/gawk/manual/gawk.html#Splitting-By-Content):
$ awk -vFPAT='([^,]*)|("[^"]+")' -vOFS=, '{print $1,$4}' file
"abc@xyz.com,www.example.com",field4
"def@xyz.com",field4
并查看What's the most robust way to efficiently parse CSV using awk?以更一般地解析字段中包含换行符等的CSV。
答案 1 :(得分:10)
这不是bash / awk解决方案,但我建议使用CSVKit,pip install csvkit
可以安装csvcut --columns=1,4 <<EOF
"abc@xyz.com,www.example.com",field2,field3,field4
"def@xyz.com",field2,field3,field4
EOF
。它提供了一系列专门用于CSV的命令行工具,包括csvcut
,它完全符合您的要求:
"abc@xyz.com,www.example.com",field4
def@xyz.com,field4
输出:
{{1}}
它删除了不必要的引号,我认为这不应该是一个问题。
阅读CSVKit here on RTD的文档。 ThoughtBot有一个nice little blog post介绍了这个工具,这是我学习CSVKit的地方。
答案 2 :(得分:4)
在您的示例输入文件中,它是引用的第一个字段,只有第一个字段。如果这一般是正确的,那么请考虑以下作为删除第二和第三列的方法:
$ awk -F, '{for (i=1;i<=NF;i++){printf "%s%s",(i>1)?",":"",$i; if ($i ~ /"$/)i=i+2};print""}' file
"abc@xyz.com,www.example.com",field4
"def@xyz.com",field4
正如评论中所提到的,awk本身并不理解引用的分隔符。此解决方案通过查找以引号结尾的第一个字段来解决此问题。然后它会跳过后面的两个字段。
for (i=1;i<=NF;i++)
这会在每个字段for
上开始i
。
printf "%s%s",(i>1)?",":"",$i
这会打印字段i
。如果它不是第一个字段,则该字段前面有逗号。
if ($i ~ /"$/)i=i+2
如果当前字段以双引号结束,则会将字段计数器增加2.这就是我们跳过字段2和3的方式。
print""
完成for
循环后,会打印换行符。
答案 3 :(得分:1)
无论引用字段在哪里,此awk都应该有效,并且也适用于转义引号。
awk '{while(match($0,/"[^"]+",|([^,]+(,|$))/,a)){
$0=substr($0,RSTART+RLENGTH);b[++x]=a[0]}
print b[1] b[4];x=0}' file
"abc@xyz.com,www.example.com",field2,field3,field4
"def@xyz.com",field2,field3,field4
field1,"abc@xyz.com,www.example.com",field3,field4
"abc@xyz.com,www.example.com",field4
"def@xyz.com",field4
field1,field4
它甚至适用于
field1,"field,2","but this field has ""escaped"\" quotes",field4
强大的FPAT变量失败了!
while(match($0,/"[^"]+",|([^,]+(,|$))/,a))
只要匹配成功(即有一个字段),就会启动一个while循环
匹配匹配正则表达式的第一次出现,它偶然匹配字段并将其存储在数组a
$0=substr($0,RSTART+RLENGTH);b[++x]=a[0]
将$0
设置为从匹配字段的末尾开始,并将匹配的字段添加到b
中的相应数组位置。
print b[1] b[4];x=0}
从b
打印所需的字段,并为下一行将x设置为零。
如果字段包含转义引号和逗号
,则会失败已更新以支持空字段
awk '{while(match($0,/("[^"]+",|[^,]*,|([^,]+$))/,a)){
$0=substr($0,RSTART+RLENGTH);b[++x]=a[0]}
print b[1] b[4];x=0}' file