在 CSV 的特定字符串之后打印 3 个连续的列

print 3 consecutive column after specific string from CSV

我需要在特定字符串后打印 2 列(在我的例子中是 64)。同一 CSV 行中可以有多个 64 实例,但是下一个实例不会出现在前一个实例的 3 列内。每个实例的输出应该在下一行并且是唯一的。问题是,特定字符串不会落在所有行的同一列中。所有行都有某种动态数据,CSV 没有 header。比方说,下面是输入文件(它只是一个示例,实际文件有大约 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

不存在与性能相关的问题。我试图搜索许多线程,但找不到任何相关的东西。请帮忙

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

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

有多种方法可以使用单个 awk 命令来完成此操作,但这对我来说感觉又快又简单。

尽管问题中的示例数据包含冗余行,但 karakfa(见下文)提醒我该问题涉及 "unique data" 要求。此版本使用关联数组的键来跟踪重复记录。

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

傻眼:

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

Sed 的乐趣

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

假设列由空格 space 或逗号分隔 需要一个 sort -u 用于 uniq(可能在 sed 中,但在这种情况下要添加一个新的 "simple" 同类动作)

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。您的示例输出与给定的输入不匹配。