【问题标题】:linux csv file concatenate columns into one columnlinux csv文件将列连接成一列
【发布时间】:2018-08-14 14:05:50
【问题描述】:

我一直在寻找使用 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}'

【问题讨论】:

  • 在盲目应用之前,请阅读标签的描述。我刚刚删除了误用的“linux”标签。
  • @UlrichEckhardt imo,标记 linux 确实有助于 cli 解决方案.. 因为awk/sed/etc 的 GNU 版本具有 POSIX 定义之外的附加功能..
  • 首先,您可以提及您使用的是 GNU(而不是 Linux!)版本的工具。其次,阅读描述:它清楚地谈到了 Linux 特定的 API。许多 GNU 程序也运行在其他操作系统内核之上,它们不是特定于 Linux 的。
  • 是的,这是一种方式……或者使用gnu标签……但我发现linux标签在这种情况下更常见

标签: awk sed command-line cut


【解决方案1】:

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

输出:

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

【讨论】:

    【解决方案2】:

    使用 GNU awk 将第三个 arg 用于 match() 和 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】:

      如果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} 要更改的字段
      • $&amp;=~tr|,||dr 使用tr 删除逗号
      • e 这个修饰符允许在替换部分使用 Perl 代码
      • 此解决方案还具有额外的优势,即使输入字段小于 14 也能正常工作

      【讨论】:

      • Perl 很棒。自 90 年代末以来我就没有使用过 Perl,所以我最初尝试使用 awk,然后尝试使用 sed,甚至尝试使用 cut。谢谢。
      【解决方案4】:

      你可以试试这个 gnu sed

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

      【讨论】:

        【解决方案5】:

        第一个变体 - 使用 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
        

        【讨论】:

        • 在您的第二个解决方案中,您应该将 # 替换为 \n,因为它已经是 GNU-only,即使输入包含 #s 也可以工作。
        【解决方案6】:

        使用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
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-12-06
          • 2021-08-17
          • 1970-01-01
          • 1970-01-01
          • 2016-08-12
          • 2013-04-03
          • 2014-01-14
          • 2018-03-30
          相关资源
          最近更新 更多