linux csv文件将列连接成一列

时间:2018-03-06 16:21:52

标签: awk sed command-line cut

我一直在寻求用sed,awk或cut做这件事。我愿意使用任何其他命令行程序来管理数据。

我有一大堆以逗号分隔的数据。行有14到20列。我需要递归地连接第10列和每行第11列,这样每行只有14列。换句话说,这个:

a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p

将成为:

a,b,c,d,e,f,g,h,i,jkl,m,n,o,p

我可以获得前10列。我可以得到最后的N列。我可以连接列。我无法想到如何在一行中完成它,所以我可以通过它传递无穷无尽的数据流,最终每行只有14列。

示例(按要求):

行中有多少列?

sed 's/[^,]//g' | wc -c

获取前10列:

cut -d, -f1-10

获取最后4列:

rev | cut -d, -f1-4 | rev

连接第10列和第11列,之后显示第1-10列:

awk -F',' ' NF { print $1","$2","$3","$4","$5","$6","$7","$8","$9","$10$11}'

6 个答案:

答案 0 :(得分:3)

var characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890 "; 解决方案:

Awk

输出:

awk 'BEGIN{ FS=OFS="," }
     { 
         diff = NF - 14;
         for (i=1; i <= NF; i++)
             printf "%s%s", $i, (diff > 1 && i >= 10 && i < (10+diff)?
                                 "": (i == NF? ORS : ",")) 
     }' file

答案 1 :(得分:2)

如果perl没问题,可以像awk一样用于流处理

$ cat ip.txt 
a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p
1,2,3,4,5,6,3,4,2,4,3,4,3,2,5,2,3,4
1,2,3,4,5,6,3,4,2,4,a,s,f,e,3,4,3,2,5,2,3,4
$ awk -F, '{print NF}' ip.txt 
16
18
22

$ perl -F, -lane '$n = $#F - 4;
                  print join ",", (@F[0..8], join("", @F[9..$n]), @F[$n+1..$#F])
                 ' ip.txt
a,b,c,d,e,f,g,h,i,jkl,m,n,o,p
1,2,3,4,5,6,3,4,2,43432,5,2,3,4
1,2,3,4,5,6,3,4,2,4asfe3432,5,2,3,4
  • -F, -lane拆分保存在,数组
  • 中的@F个结果
  • $n = $#F - 4幻数,确保输出结束14列。 $#F给出数组的最后一个元素的索引(如果输入行少于14列,则不会工作)
  • join有助于将数组元素与指定的字符串
  • 组合在一起
  • @F[0..8]带有前9个元素的数组切片
  • 根据需要
  • @F[9..$n]@F[$n+1..$#F]其他切片


借鉴Ed Morton's regex based solution

$ perl -F, -lape '$n=$#F-13; s/^([^,]*,){9}\K([^,]*,){$n}/$&=~tr|,||dr/e' ip.txt
a,b,c,d,e,f,g,h,i,jkl,m,n,o,p
1,2,3,4,5,6,3,4,2,43432,5,2,3,4
1,2,3,4,5,6,3,4,2,4asfe3432,5,2,3,4
  • $n=$#F-13幻数
  • ^([^,]*,){9}\K前9个字段
  • ([^,]*,){$n}要更改的字段
  • $&=~tr|,||dr使用tr删除逗号
  • e此修饰符允许在替换部分
  • 中使用Perl代码
  • 即使输入字段小于14
  • ,此解决方案还具有工作的附加优势

答案 2 :(得分:2)

使用GNU awk为第3个arg匹配()和gensub():

$ cat tst.awk
BEGIN{ FS="," }
match($0,"(([^,]+,){9})(([^,]+,){"NF-14"})(.*)",a) {
    $0 = a[1] gensub(/,/,"","g",a[3]) a[5]
}
{ print }

$ awk -f tst.awk file
a,b,c,d,e,f,g,h,i,jkl,m,n,o,p

答案 3 :(得分:1)

你可以试试这个gnu sed

sed -E '
s/,/\n/9g
:A
s/([^\n]*\n)(.*)(\n)(([^\n]*\n){4})/\1\2\4/
tA
s/\n/,/g
' infile

答案 4 :(得分:1)

第一个变种 - 使用awk

awk -F, '
{
    for(i = 1; i <= NF; i++) {
        OFS = (i > 9 && i < NF - 4) ? "" : ","
        if(i == NF) OFS = "\n"
        printf "%s%s", $i, OFS 
    }
}' input.txt

第二个变种 - 使用sed

sed -r 's/,/#/10g; :l; s/#(.*)((#[^#]){4})/\1\2/; tl; s/#/,/g' input.txt

或者,更直接(没有循环),可能更快。

sed -r 's/,(.),(.),(.),(.)$/#\1#\2#\3#\4/; s/,//10g; s/#/,/g' input.txt

测试

<强>输入

a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p
a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r
a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u

<强>输出

a,b,c,d,e,f,g,h,i,jkl,m,n,o,p
a,b,c,d,e,f,g,h,i,jklmn,o,p,q,r
a,b,c,d,e,f,g,h,i,jklmnopq,r,s,t,u

答案 5 :(得分:0)

使用csvtool解决了类似的问题。源文件,是从其他答案之一复制的:

$ cat input.txt
a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p
1,2,3,4,5,6,3,4,2,4,3,4,3,2,5,2,3,4
1,2,3,4,5,6,3,4,2,4,a,s,f,e,3,4,3,2,5,2,3,4

串联列:

$ cat input.txt | csvtool format '%1,%2,%3,%4,%5,%6,%7,%8,%9,%10%11%12,%13,%14,%15,%16,%17,%18,%19,%20,%21,%22\n' -
a,b,c,d,e,f,g,h,i,jkl,m,n,o,p,,,,,,
1,2,3,4,5,6,3,4,2,434,3,2,5,2,3,4,,,,
1,2,3,4,5,6,3,4,2,4as,f,e,3,4,3,2,5,2,3,4
anatoly@anatoly-workstation:cbs$ cat input.txt