从CSV

时间:2015-12-03 05:41:21

标签: shell awk sed opencsv

我需要在特定字符串后打印2列(在我的例子中是64)。在同一CSV行中可能有多个64个实例,但是下一个实例不会出现在上一次出现的3列中。每个实例的输出应该在下一行并且是唯一的。问题是,特定字符串不会落在所有行的同一列中。所有行都有一些动态数据,没有CSV标题。比方说,下面是输入文件(它只是一个样本,实际文件有大约300列和500万个原始文件):

00:TEST,123453103279586,ABC,XYZ,123,456,65,906,06149,NIL TS21,1,64,906,06149,NIL TS22,1,64,916,06149,NIL BS20,1,64,926,06149,NIL BS30,1,64,906,06149,NIL CAML,1,ORIG,0,TERM,1,1,1,6422222222    
00:TEST,123458131344169,ABC,XYZ,123,456,OCCF,1,1,1,64,857,19066,NIL TS21,1,64,857,19066,NIL TS22,1,64,857,19066,NIL BS20,1,64,857,19067,NIL BS30,1,64,857,19068,NIL PSS,1,E2  EPSDATA,GRANTED,NONE,1,N,N,256000,5    
00:TEST,123458131016844,ABC,XYZ,123,456,HOLD,,1,64,938,36843,NIL TS21,1,64,938,36841,NIL TS22,1,64,938,36823,NIL BS20,1,64,938,36843,NIL BS30,1,64,938,36843,NIL CAML,1,ORIG,0,TERM,00,50000,N,N,N,N    
00:TEST,123453102914690,ABC,XYZ,123,456,HOLD,,1,PBS,TS11,64,938,64126,NIL TS21,1,64,938,64126,NIL TS22,1,64,938,64126,NIL BS20,1,64,938,64226,NIL BS30,1,64,938,64326,NIL CAML,1,ORIG,0,TERM,1,1,1,6422222222,2222,R

需要输出(仅限唯一条目):

64,906,06149
64,857,19066
64,857,19067
64,857,19068
64,938,36843
64,938,36841
64,938,36823
64,938,36843
64,938,36843
64,938,64326

没有与性能相关的问题。我试图搜索许多线程,但无法得到任何相关的东西。请帮忙。

4 个答案:

答案 0 :(得分:1)

我们可以使用两个命令的管道...首先将64的前导放在一行上,如果我们看到前导64,则先打印前三列。

sed 's/,64[,\n]/\n64,/g' | awk -F, '/^64/ { print $1 FS $2 FS $3 }'

使用单个 awk 命令可以做到这一点,但这对我来说感觉很快捷。

虽然问题的样本数据包含冗余行,但karakfa(见下文)提醒我,问题是“独特数据”要求。此版本使用关联数组的键来跟踪重复记录。

sed 's/,64[,\n]/\n64,/g' | awk -F, 'BEGIN { split("",a) } /^64/ && !((x=$1 FS $2 FS $3) in a) { a[x]=1; print x }'

答案 1 :(得分:0)

GAWK:

awk -F, '{for(i=0;++i<=NF;){if($i=="64")a=4;if(--a>0)s=s?s","$i:$i;if(a==1){print s;s=""}}}' file

答案 2 :(得分:0)

Sed for fun

sed -n -e 's/$/,n,n,n/' -e ':a' -e 'G;s/[[:blank:],]\(64,.*\)\(\n\)$/\2\1/;s/.*\(\n\)\(64\([[:blank:],][^[:blank:],]\{1,\}\)\{2\}\)\([[:blank:],][^[:blank:],]\{1,\}\)\{3\}\([[:blank:],].*\)\{0,1\}$/\1\2\1\5/;s/^.*\n\(.*\n\)/\1/;/^64.*\n/P;s///;ta' YourFile | sort -u

假设列由空格或逗号分隔 需要对uniq进行排序-u(可能在sed中,但是新的&#34;简单&#34;在这种情况下添加相同类型的动作)

答案 3 :(得分:0)

awk救援!

$ awk -F, '{for(i=1;i<=NF;i++) 
               if($i==64) 
                 {k=$i FS $(++i) FS $(++i); 
                  if (!a[k]++) 
                      print k 
                 }
           }' file
64,906,06149
64,916,06149
64,926,06149
64,857,19066
64,857,19067
64,857,19068
64,938,36843
64,938,36841
64,938,36823
64,938,64126
64,938,64226
64,938,64326

PS。您的示例输出与给定输入不匹配。